mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eac07df96c | ||
|
|
8c1376df07 | ||
|
|
45d68d9b39 | ||
|
|
c371b853af | ||
|
|
bc32a63c69 | ||
|
|
4b26546589 | ||
|
|
bc56788fe6 | ||
|
|
b4d41c1b7a | ||
|
|
36a033b87a | ||
|
|
9544ba1029 | ||
|
|
1a7bb5a400 | ||
|
|
48c35bcfbc | ||
|
|
ec2d4bd3ee | ||
|
|
ce9fa6ebbf | ||
|
|
9a9007abae | ||
|
|
88ec6f6b16 | ||
|
|
795b6e3480 | ||
|
|
9bdb0a12e4 | ||
|
|
2cdd61294f | ||
|
|
627cdc07d0 | ||
|
|
a47a62172a | ||
|
|
f72e5a8f05 | ||
|
|
fbe91a67a4 | ||
|
|
6dcecb38a4 | ||
|
|
dcfb427b09 | ||
|
|
ad03d180c9 | ||
|
|
3232a4d60d | ||
|
|
3aff590855 | ||
|
|
c8babbad27 | ||
|
|
c6dad28ddc | ||
|
|
fea81419cd | ||
|
|
83be517e77 | ||
|
|
79a569422c | ||
|
|
1e0b12e37e | ||
|
|
dc15032112 | ||
|
|
2821227acf | ||
|
|
2191ef7eee | ||
|
|
4c2cf6da75 | ||
|
|
0f3d6d871e | ||
|
|
bd007d4617 | ||
|
|
ead4f7af9e | ||
|
|
4808b5b3ba | ||
|
|
f3da6796b9 | ||
|
|
cece12e87e | ||
|
|
68d1727cac | ||
|
|
8a2e13b20a | ||
|
|
ee311b8e5c | ||
|
|
f0de6c4e92 | ||
|
|
1c4c8764ed | ||
|
|
e6161a6f58 | ||
|
|
8c0fe59c90 | ||
|
|
17690b3add | ||
|
|
f9987c8bed | ||
|
|
8109cbad97 | ||
|
|
c5bb32253b | ||
|
|
5b1e673cec | ||
|
|
2cd06826c0 | ||
|
|
4f0c5a8d49 | ||
|
|
3011251da7 | ||
|
|
76b4cb5c00 | ||
|
|
f83af3c25d | ||
|
|
e3931718fb | ||
|
|
4cde86643e | ||
|
|
9ee3207280 | ||
|
|
e696a07190 | ||
|
|
e0db987441 | ||
|
|
1890b0019d | ||
|
|
a750e4a1a3 | ||
|
|
1c789dda08 | ||
|
|
4086d463a9 | ||
|
|
b8368de6d5 | ||
|
|
7dc90094d2 | ||
|
|
ba85ca32c4 | ||
|
|
70946b85e5 | ||
|
|
1570c328c6 | ||
|
|
9288fccf07 | ||
|
|
5e1d7c3076 | ||
|
|
89d5186c0d | ||
|
|
aaad60d07e | ||
|
|
5f16469807 | ||
|
|
752bc27e2b | ||
|
|
cc6a14104d | ||
|
|
eb13c2b6af | ||
|
|
63c133e4a3 | ||
|
|
b8d59d699b | ||
|
|
5586613eec | ||
|
|
ad8e6dc63b | ||
|
|
f72e0ca979 | ||
|
|
03cfe67500 | ||
|
|
7a252c4755 | ||
|
|
2089901739 | ||
|
|
635e506c16 | ||
|
|
75d8c7e3cc | ||
|
|
080d6cdd11 | ||
|
|
433d2115bc | ||
|
|
34e31232df | ||
|
|
7fca1d28af | ||
|
|
9c3d765403 | ||
|
|
bb652ceb91 | ||
|
|
62696f5819 | ||
|
|
41170ce341 | ||
|
|
e2092a4ddd | ||
|
|
fd1441d122 | ||
|
|
e1422c6443 | ||
|
|
1f07fd4150 | ||
|
|
9b92aa08ae | ||
|
|
8bf8cbbd61 | ||
|
|
f507844102 | ||
|
|
fffbb60ed9 | ||
|
|
9aec4abc4d | ||
|
|
a53b3f199f | ||
|
|
d6d696b66a | ||
|
|
ca6bf966dd | ||
|
|
5a9f8860ca | ||
|
|
5423bc66a9 | ||
|
|
187d2ad226 | ||
|
|
7cf0d5d15e | ||
|
|
1f2ee8cb62 | ||
|
|
35c3d0b3fc | ||
|
|
0279294972 | ||
|
|
7eddee6f7a | ||
|
|
f2c48cfac5 | ||
|
|
6ae0a00211 | ||
|
|
bfcf38c8bc | ||
|
|
9e328da641 | ||
|
|
e336d04c79 | ||
|
|
a71bc62c29 | ||
|
|
4b0b7093e5 | ||
|
|
8387de64d3 | ||
|
|
77de6e5d6a | ||
|
|
8c867a001a | ||
|
|
d01a71f7de | ||
|
|
04d1d4c00e | ||
|
|
d7e58ee1af | ||
|
|
ffb165ce26 | ||
|
|
65cb09eb2e | ||
|
|
78552ebd7a | ||
|
|
0c7bd12372 | ||
|
|
3d11d7685b | ||
|
|
592ae6b4d2 | ||
|
|
4fa79ee02f | ||
|
|
fbd0ccbd5b | ||
|
|
8c008a0e7d | ||
|
|
11fe19d08a | ||
|
|
1b3469f236 | ||
|
|
022921168d | ||
|
|
c6765eb3eb | ||
|
|
c5a374fbf2 |
4
.clog.toml
Normal file
4
.clog.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[clog]
|
||||
|
||||
repository = "https://github.com/rust-lang/rustlings"
|
||||
changelog = "CHANGELOG.md"
|
||||
7
.editorconfig
Normal file
7
.editorconfig
Normal 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
1
.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
*.swp
|
||||
target/
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
.DS_Store
|
||||
|
||||
@@ -3,7 +3,7 @@ rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
script: cargo test --verbose -- --test-threads=1
|
||||
script: cargo test --verbose
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
|
||||
160
CHANGELOG.md
Normal file
160
CHANGELOG.md
Normal 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
131
CONTRIBUTING.md
Normal 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
961
Cargo.lock
generated
Normal 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"
|
||||
@@ -1,16 +1,17 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "1.1.0"
|
||||
authors = ["Olivia <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"
|
||||
@@ -18,3 +19,5 @@ path = "src/main.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "0.11.0"
|
||||
predicates = "1.0.1"
|
||||
glob = "0.3.0"
|
||||
|
||||
76
README.md
76
README.md
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# rustlings 🦀❤️
|
||||
|
||||
@@ -31,44 +31,64 @@ curl -L https://git.io/rustlings | bash -s mypath/
|
||||
|
||||
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
|
||||
|
||||
## Windows/Manually
|
||||
## 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/1.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
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 .
|
||||
```
|
||||
|
||||
Same as above, run `rustlings` to get started.
|
||||
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
|
||||
```
|
||||
|
||||
In case you get stuck, there is usually a hint at the bottom of each exercise.
|
||||
In case you get stuck, you can run the following command to get a hint for your
|
||||
exercise:
|
||||
|
||||
``` bash
|
||||
rustlings hint myExercise1
|
||||
```
|
||||
|
||||
## Testing yourself
|
||||
|
||||
@@ -94,31 +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`.
|
||||
|
||||
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]]
|
||||
+ path = "exercises/yourTopic/yourTopicN.rs"
|
||||
+ mode = "compile"
|
||||
...
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
@@ -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!
|
||||
7
exercises/enums/README.md
Normal file
7
exercises/enums/README.md
Normal 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
16
exercises/enums/enums1.rs
Normal 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
28
exercises/enums/enums2.rs
Normal 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
65
exercises/enums/enums3.rs
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
37
exercises/error_handling/errors1.rs
Executable file → Normal 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
33
exercises/error_handling/errors2.rs
Executable file → Normal 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/book/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
41
exercises/error_handling/errors3.rs
Executable file → Normal 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
48
exercises/error_handling/errorsn.rs
Executable file → Normal 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
48
exercises/error_handling/option1.rs
Executable file → Normal 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
32
exercises/error_handling/result1.rs
Executable file → Normal 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 :)
|
||||
|
||||
@@ -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
42
exercises/functions/functions1.rs
Executable file → Normal 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
34
exercises/functions/functions2.rs
Executable file → Normal 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
34
exercises/functions/functions3.rs
Executable file → Normal 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
26
exercises/functions/functions4.rs
Executable file → Normal 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
40
exercises/functions/functions5.rs
Executable file → Normal 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`
|
||||
|
||||
@@ -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
40
exercises/if/if1.rs
Executable file → Normal 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.
|
||||
|
||||
@@ -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
56
exercises/macros/macros1.rs
Executable file → Normal 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
65
exercises/macros/macros2.rs
Executable file → Normal 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
66
exercises/macros/macros3.rs
Executable file → Normal 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
65
exercises/macros/macros4.rs
Executable file → Normal 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.
|
||||
|
||||
@@ -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
35
exercises/modules/modules1.rs
Executable file → Normal 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
36
exercises/modules/modules2.rs
Executable file → Normal 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.
|
||||
|
||||
@@ -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
23
exercises/move_semantics/move_semantics1.rs
Executable file → Normal 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
34
exercises/move_semantics/move_semantics2.rs
Executable file → Normal 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
26
exercises/move_semantics/move_semantics3.rs
Executable file → Normal 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
30
exercises/move_semantics/move_semantics4.rs
Executable file → Normal 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`
|
||||
|
||||
@@ -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
2
exercises/primitive_types/primitive_types1.rs
Executable file → Normal 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
2
exercises/primitive_types/primitive_types2.rs
Executable file → Normal 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
38
exercises/primitive_types/primitive_types3.rs
Executable file → Normal 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
45
exercises/primitive_types/primitive_types4.rs
Executable file → Normal 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
39
exercises/primitive_types/primitive_types5.rs
Executable file → Normal 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
40
exercises/primitive_types/primitive_types6.rs
Executable file → Normal 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!
|
||||
|
||||
@@ -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
33
exercises/standard_library_types/arc1.rs
Executable file → Normal 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.
|
||||
|
||||
48
exercises/standard_library_types/iterators2.rs
Normal file
48
exercises/standard_library_types/iterators2.rs
Normal 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");
|
||||
}
|
||||
}
|
||||
81
exercises/standard_library_types/iterator3.rs → exercises/standard_library_types/iterators3.rs
Executable file → Normal file
81
exercises/standard_library_types/iterator3.rs → exercises/standard_library_types/iterators3.rs
Executable file → Normal 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
33
exercises/standard_library_types/iterators4.rs
Executable file → Normal 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.
|
||||
|
||||
@@ -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
40
exercises/strings/strings1.rs
Executable file → Normal 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
34
exercises/strings/strings2.rs
Executable file → Normal 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.
|
||||
|
||||
7
exercises/structs/README.md
Normal file
7
exercises/structs/README.md
Normal 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)
|
||||
45
exercises/structs/structs1.rs
Normal file
45
exercises/structs/structs1.rs
Normal 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!");
|
||||
}
|
||||
}
|
||||
47
exercises/structs/structs2.rs
Normal file
47
exercises/structs/structs2.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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
38
exercises/test2.rs
Executable file → Normal 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
43
exercises/test3.rs
Executable file → Normal 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)`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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
38
exercises/tests/tests1.rs
Executable file → Normal 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
37
exercises/tests/tests2.rs
Executable file → Normal 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
30
exercises/tests/tests3.rs
Executable file → Normal 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())`.
|
||||
|
||||
@@ -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
74
exercises/threads/threads1.rs
Executable file → Normal 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 :)
|
||||
|
||||
@@ -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
44
exercises/variables/variables1.rs
Executable file → Normal 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
40
exercises/variables/variables2.rs
Executable file → Normal 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
38
exercises/variables/variables3.rs
Executable file → Normal 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
42
exercises/variables/variables4.rs
Executable file → Normal 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!
|
||||
|
||||
447
info.toml
447
info.toml
@@ -1,213 +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 = "compile"
|
||||
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!"""
|
||||
|
||||
# TESTS
|
||||
# STRUCTS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests1.rs"
|
||||
name = "structs1"
|
||||
path = "exercises/structs/structs1.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests2.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests3.rs"
|
||||
mode = "test"
|
||||
|
||||
# TEST 2
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test2.rs"
|
||||
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 = "compile"
|
||||
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 = "compile"
|
||||
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"
|
||||
|
||||
# THREADS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/threads/threads1.rs"
|
||||
mode = "compile"
|
||||
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]]
|
||||
path = "exercises/standard_library_types/iterator3.rs"
|
||||
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
85
install.ps1
Normal 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."
|
||||
21
install.sh
21
install.sh
@@ -3,31 +3,31 @@
|
||||
echo "Let's get you set up with Rustlings!"
|
||||
|
||||
echo "Checking requirements..."
|
||||
if [ -x "$(git)" ]
|
||||
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
|
||||
else
|
||||
echo "SUCCESS: Git is installed"
|
||||
fi
|
||||
|
||||
if [ -x "$(rustc)" ]
|
||||
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
|
||||
else
|
||||
echo "SUCCESS: Rust is installed"
|
||||
fi
|
||||
|
||||
if [ -x "$(cargo)" ]
|
||||
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
|
||||
else
|
||||
echo "SUCCESS: Cargo is installed"
|
||||
fi
|
||||
|
||||
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
|
||||
@@ -94,10 +94,9 @@ git checkout -q tags/$Version
|
||||
echo "Installing the 'rustlings' executable..."
|
||||
cargo install --force --path .
|
||||
|
||||
if [ -x "$(rustlings)" ]
|
||||
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
194
src/exercise.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
111
src/main.rs
111
src/main.rs
@@ -1,20 +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::ffi::OsStr;
|
||||
use std::io::BufRead;
|
||||
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() {
|
||||
@@ -28,14 +26,16 @@ 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!(r#" welcome to... "#);
|
||||
@@ -53,52 +53,87 @@ fn main() {
|
||||
"{} 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) = matches.subcommand_matches("run") {
|
||||
run(matches.clone()).unwrap();
|
||||
if !rustc_exists() {
|
||||
println!("We cannot find `rustc`.");
|
||||
println!("Try running `rustc --version` to diagnose your problem.");
|
||||
println!("For instructions on how to install Rust, check the README.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let toml_str = &fs::read_to_string("info.toml").unwrap();
|
||||
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
|
||||
|
||||
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 Some(ref matches) = matches.subcommand_matches("hint") {
|
||||
let name = matches.value_of("name").unwrap();
|
||||
|
||||
let exercise = exercises
|
||||
.iter()
|
||||
.find(|e| name == e.name)
|
||||
.unwrap_or_else(|| {
|
||||
println!("No exercise found for your given name!");
|
||||
std::process::exit(1)
|
||||
});
|
||||
|
||||
println!("{}", exercise.hint);
|
||||
}
|
||||
|
||||
if matches.subcommand_matches("verify").is_some() {
|
||||
match verify(None) {
|
||||
Ok(_) => {}
|
||||
Err(_) => std::process::exit(1),
|
||||
}
|
||||
verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if matches.subcommand_matches("watch").is_some() {
|
||||
watch().unwrap();
|
||||
watch(&exercises).unwrap();
|
||||
}
|
||||
|
||||
if matches.subcommand_name().is_none() {
|
||||
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(®ions[..], true));
|
||||
}
|
||||
let text = fs::read_to_string("default_out.txt").unwrap();
|
||||
println!("{}", text);
|
||||
}
|
||||
|
||||
println!("\x1b[0m");
|
||||
}
|
||||
|
||||
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(None);
|
||||
clear_screen();
|
||||
let _ignored = verify(exercises.iter());
|
||||
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(event) => match event {
|
||||
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
|
||||
if b.extension() == Some(OsStr::new("rs")) {
|
||||
println!("----------**********----------\n");
|
||||
let _ignored = verify(Some(b.as_path().to_str().unwrap()));
|
||||
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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -107,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)
|
||||
}
|
||||
|
||||
56
src/run.rs
56
src/run.rs
@@ -1,60 +1,40 @@
|
||||
use crate::util::clean;
|
||||
use crate::exercise::{Exercise, Mode};
|
||||
use crate::verify::test;
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use toml::Value;
|
||||
|
||||
pub fn run(matches: clap::ArgMatches) -> Result<(), ()> {
|
||||
if let Some(filename) = matches.value_of("file") {
|
||||
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
|
||||
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
|
||||
let mut exercises = tomlvec.clone();
|
||||
exercises.retain(|i| i.get("path").unwrap().as_str().unwrap() == filename);
|
||||
if exercises.is_empty() {
|
||||
println!("No exercise found for your filename!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let exercise: &Value = &exercises[0];
|
||||
match exercise.get("mode").unwrap().as_str().unwrap() {
|
||||
"test" => test(exercise.get("path").unwrap().as_str().unwrap())?,
|
||||
"compile" => compile_and_run(exercise.get("path").unwrap().as_str().unwrap())?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
panic!("Please supply a filename!");
|
||||
pub fn run(exercise: &Exercise) -> Result<(), ()> {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(exercise)?,
|
||||
Mode::Compile => compile_and_run(exercise)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_and_run(filename: &str) -> Result<(), ()> {
|
||||
pub fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", filename).as_str());
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compilecmd = Command::new("rustc")
|
||||
.args(&[filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
progress_bar.set_message(format!("Running {}...", filename).as_str());
|
||||
|
||||
let compilecmd = exercise.compile();
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
if compilecmd.status.success() {
|
||||
let runcmd = Command::new("./temp").output().expect("fail");
|
||||
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("✅", "✓"), filename);
|
||||
let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
|
||||
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), filename);
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
|
||||
println!("{}", style(formatstr).red());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
@@ -62,11 +42,11 @@ pub fn compile_and_run(filename: &str) -> Result<(), ()> {
|
||||
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();
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
12
src/util.rs
12
src/util.rs
@@ -1,12 +0,0 @@
|
||||
use std::fs::remove_file;
|
||||
|
||||
pub fn clean() {
|
||||
let _ignored = remove_file("temp");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clean() {
|
||||
std::fs::File::create("temp").unwrap();
|
||||
clean();
|
||||
assert!(!std::path::Path::new("temp").exists());
|
||||
}
|
||||
140
src/verify.rs
140
src/verify.rs
@@ -1,93 +1,79 @@
|
||||
use crate::util::clean;
|
||||
use crate::exercise::{Exercise, Mode, State};
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use toml::Value;
|
||||
|
||||
pub fn verify(start_at: Option<&str>) -> Result<(), ()> {
|
||||
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
|
||||
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
|
||||
let mut hit_start_at = false;
|
||||
|
||||
for i in tomlvec {
|
||||
let path = i.get("path").unwrap().as_str().unwrap();
|
||||
|
||||
if let Some(start_at) = start_at {
|
||||
if start_at.ends_with(path) {
|
||||
hit_start_at = true;
|
||||
} else if !hit_start_at {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
match i.get("mode").unwrap().as_str().unwrap() {
|
||||
"test" => test(path)?,
|
||||
"compile" => compile_only(path)?,
|
||||
_ => (),
|
||||
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<(), ()> {
|
||||
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 {}...", filename).as_str());
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compilecmd = Command::new("rustc")
|
||||
.args(&[filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
let compile_output = exercise.compile();
|
||||
progress_bar.finish_and_clear();
|
||||
if compilecmd.status.success() {
|
||||
let formatstr = format!(
|
||||
"{} Successfully compiled {}!",
|
||||
Emoji("✅", "✓"),
|
||||
filename
|
||||
);
|
||||
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<(), ()> {
|
||||
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 {}...", filename).as_str());
|
||||
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let testcmd = Command::new("rustc")
|
||||
.args(&["--test", filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
if testcmd.status.success() {
|
||||
progress_bar.set_message(format!("Running {}...", filename).as_str());
|
||||
let runcmd = Command::new("./temp").output().expect("fail");
|
||||
|
||||
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 {
|
||||
@@ -95,11 +81,49 @@ pub fn test(filename: &str) -> Result<(), ()> {
|
||||
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
|
||||
}
|
||||
|
||||
3
tests/fixture/failure/compFailure.rs
Normal file
3
tests/fixture/failure/compFailure.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
let
|
||||
}
|
||||
11
tests/fixture/failure/info.toml
Normal file
11
tests/fixture/failure/info.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[[exercises]]
|
||||
name = "compFailure"
|
||||
path = "compFailure.rs"
|
||||
mode = "compile"
|
||||
hint = ""
|
||||
|
||||
[[exercises]]
|
||||
name = "testFailure"
|
||||
path = "testFailure.rs"
|
||||
mode = "test"
|
||||
hint = "Hello!"
|
||||
4
tests/fixture/failure/testFailure.rs
Normal file
4
tests/fixture/failure/testFailure.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[test]
|
||||
fn passing() {
|
||||
asset!(true);
|
||||
}
|
||||
4
tests/fixture/failure/testNotPassed.rs
Normal file
4
tests/fixture/failure/testNotPassed.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[test]
|
||||
fn not_passing() {
|
||||
assert!(false);
|
||||
}
|
||||
5
tests/fixture/state/finished_exercise.rs
Normal file
5
tests/fixture/state/finished_exercise.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// fake_exercise
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
11
tests/fixture/state/info.toml
Normal file
11
tests/fixture/state/info.toml
Normal 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 = """"""
|
||||
7
tests/fixture/state/pending_exercise.rs
Normal file
7
tests/fixture/state/pending_exercise.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
// fake_exercise
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
4
tests/fixture/state/pending_test_exercise.rs
Normal file
4
tests/fixture/state/pending_test_exercise.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
// I AM NOT DONE
|
||||
|
||||
#[test]
|
||||
fn it_works() {}
|
||||
@@ -1,7 +1,11 @@
|
||||
[[exercises]]
|
||||
name = "compSuccess"
|
||||
path = "compSuccess.rs"
|
||||
mode = "compile"
|
||||
hint = """"""
|
||||
|
||||
[[exercises]]
|
||||
name = "testSuccess"
|
||||
path = "testSuccess.rs"
|
||||
mode = "test"
|
||||
mode = "test"
|
||||
hint = """"""
|
||||
@@ -1,4 +1,8 @@
|
||||
use assert_cmd::prelude::*;
|
||||
use glob::glob;
|
||||
use predicates::boolean::PredicateBooleanExt;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::process::Command;
|
||||
|
||||
#[test]
|
||||
@@ -13,7 +17,7 @@ fn fails_when_in_wrong_dir() {
|
||||
.unwrap()
|
||||
.current_dir("tests/")
|
||||
.assert()
|
||||
.failure();
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -21,31 +25,71 @@ fn verify_all_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
.current_dir("tests/fixture/")
|
||||
.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.rs"])
|
||||
.current_dir("tests/fixture/")
|
||||
.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.rs"])
|
||||
.current_dir("tests/fixture/")
|
||||
.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")
|
||||
@@ -53,7 +97,7 @@ fn run_single_test_no_filename() {
|
||||
.arg("r")
|
||||
.current_dir("tests/fixture/")
|
||||
.assert()
|
||||
.failure();
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -61,7 +105,57 @@ fn run_single_test_no_exercise() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compNoExercise.rs"])
|
||||
.current_dir("tests/fixture/")
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.failure();
|
||||
.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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user