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

Compare commits

...

72 Commits
2.1.0 ... 3.0.0

Author SHA1 Message Date
mokou
2ff3f7ae13 3.0.0 2020-04-12 00:01:08 +02:00
fmoko
2b80f6ed41 chore: Remove duplicate option1 exercise 2020-04-11 17:27:10 +02:00
Rohan Jain
3ab084a421 fix(run): compile clippy exercise files
Additionally to running clippy, also compile the exercise file so that
`rustling run clippy1` works after a successful completion of the
exercise.

closes #291

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

* changed up the exercise, modified the help section

* Update exercises/option/option2.rs

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

* Update exercises/option/option2.rs

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

* Update exercises/option/option2.rs

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

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

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

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

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

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

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

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

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

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

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

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

closes #251

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

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

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

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

The `as` operator is also covered.
2019-12-16 16:41:03 +00:00
Abdou Seck
fc26b5e151 I AM NOT DONE comment in conversions exercise files 2019-12-16 11:33:00 -05:00
Abdou Seck
0c85dc1193 feat: Add type conversion and parsing exercises 2019-12-16 09:12:13 -05:00
marisa
fe10e06c37 fix(tests1): Change test command
Closes #243.
2019-12-16 13:05:25 +01:00
marisa
419f7797f2 fix(iterators2): Remove reference to missing iterators2.rs (#245)
fix(iterators2): Remove reference to missing iterators2.rs
2019-12-16 12:51:03 +01:00
Rahat Ahmed
54571a5fca fix(iterators2): Remove reference to missing iterators2.rs 2019-12-07 23:25:13 -08:00
41 changed files with 1163 additions and 241 deletions

3
.gitignore vendored
View File

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

View File

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

View File

@@ -1,3 +1,67 @@
<a name="3.0.0"></a>
## 3.0.0 (2020-04-11)
#### Breaking Changes
* make "compile" exercises print output (#278) ([3b6d5c](https://github.com/fmoko/rustlings/commit/3b6d5c3aaa27a242a832799eb66e96897d26fde3))
#### Bug Fixes
* **primitive_types:** revert primitive_types4 (#296) ([b3a3351e](https://github.com/rust-lang/rustlings/commit/b3a3351e8e6a0bdee07077d7b0382953821649ae))
* **run:** compile clippy exercise files (#295) ([3ab084a4](https://github.com/rust-lang/rustlings/commit/3ab084a421c0f140ae83bf1fc3f47b39342e7373))
* **conversions:**
* add additional test to meet exercise rules (#284) ([bc22ec3](https://github.com/fmoko/rustlings/commit/bc22ec382f843347333ef1301fc1bad773657f38))
* remove duplicate not done comment (#292) ([dab90f](https://github.com/fmoko/rustlings/commit/dab90f7b91a6000fe874e3d664f244048e5fa342))
* don't hardcode documentation version for traits (#288) ([30e6af](https://github.com/fmoko/rustlings/commit/30e6af60690c326fb5d3a9b7335f35c69c09137d))
#### Features
* add Option2 exercise (#290) ([86b5c08b](https://github.com/rust-lang/rustlings/commit/86b5c08b9bea1576127a7c5f599f5752072c087d))
* add excercise for option (#282) ([135e5d47](https://github.com/rust-lang/rustlings/commit/135e5d47a7c395aece6f6022117fb20c82f2d3d4))
* add new exercises for generics (#280) ([76be5e4e](https://github.com/rust-lang/rustlings/commit/76be5e4e991160f5fd9093f03ee2ba260e8f7229))
* **ci:** add buildkite config ([b049fa2c](https://github.com/rust-lang/rustlings/commit/b049fa2c84dba0f0c8906ac44e28fd45fba51a71))
<a name="2.2.1"></a>
### 2.2.1 (2020-02-27)
#### Bug Fixes
* Re-add cloning the repo to install scripts ([3d9b03c5](https://github.com/rust-lang/rustlings/commit/3d9b03c52b8dc51b140757f6fd25ad87b5782ef5))
#### Features
* Add clippy lints (#269) ([1e2fd9c9](https://github.com/rust-lang/rustlings/commit/1e2fd9c92f8cd6e389525ca1a999fca4c90b5921))
<a name="2.2.0"></a>
## 2.2.0 (2020-02-25)
#### Bug Fixes
* Update deps to version compatable with aarch64-pc-windows (#263) ([19a93428](https://github.com/rust-lang/rustlings/commit/19a93428b3c73d994292671f829bdc8e5b7b3401))
* **docs:**
* Added a necessary step to Windows installation process (#242) ([3906efcd](https://github.com/rust-lang/rustlings/commit/3906efcd52a004047b460ed548037093de3f523f))
* Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9))
* Updated iterators readme to account for iterators4 exercise (#273) ([bec8e3a](https://github.com/rust-lang/rustlings/commit/bec8e3a644cbd88db1c73ea5f1d8a364f4a34016))
* **installation:** make fatal errors more obvious (#272) ([17d0951e](https://github.com/rust-lang/rustlings/commit/17d0951e66fda8e11b204d5c4c41a0d5e22e78f7))
* **iterators2:**
* Remove reference to missing iterators2.rs (#245) ([419f7797](https://github.com/rust-lang/rustlings/commit/419f7797f294e4ce6a2b883199731b5bde77d262))
* **as_ref_mut:** Enable a test and improve per clippy's suggestion (#256) ([dfdf809](https://github.com/rust-lang/rustlings/commit/dfdf8093ebbd4145864995627b812780de52f902))
* **tests1:**
* Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce)
* Correct test command in tests1.rs comment (#263) ([39fa7ae](https://github.com/rust-lang/rustlings/commit/39fa7ae8b70ad468da49b06f11b2383135a63bcf))
#### Features
* Add variables5.rs exercise (#264) ([0c73609e](https://github.com/rust-lang/rustlings/commit/0c73609e6f2311295e95d6f96f8c747cfc4cba03))
* Show a completion message when watching (#253) ([d25ee55a](https://github.com/rust-lang/rustlings/commit/d25ee55a3205882d35782e370af855051b39c58c))
* Add type conversion and parsing exercises (#249) ([0c85dc11](https://github.com/rust-lang/rustlings/commit/0c85dc1193978b5165491b99cc4922caf8d14a65))
* Created consistent money unit (#258) ([fd57f8f](https://github.com/rust-lang/rustlings/commit/fd57f8f2c1da2af8ddbebbccec214e6f40f4dbab))
* Enable test for exercise test4 (#276) ([8b971ff](https://github.com/rust-lang/rustlings/commit/8b971ffab6079a706ac925f5917f987932b55c07))
* Added traits exercises (#274 but specifically #216, which originally added
this :heart:) ([b559cdd](https://github.com/rust-lang/rustlings/commit/b559cdd73f32c0d0cfc1feda39f82b3e3583df17))
<a name="2.1.0"></a>
## 2.1.0 (2019-11-27)

153
Cargo.lock generated
View File

@@ -1,13 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.7.3"
@@ -21,7 +13,7 @@ name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -42,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -74,17 +66,6 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clicolors-control"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clicolors-control"
version = "1.0.0"
@@ -93,7 +74,7 @@ dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -106,23 +87,7 @@ dependencies = [
[[package]]
name = "console"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"clicolors-control 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "console"
version = "0.7.5"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -134,7 +99,22 @@ dependencies = [
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "console"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -219,18 +199,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "indicatif"
version = "0.9.0"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"console 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inotify"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -269,11 +250,6 @@ dependencies = [
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.3.0"
@@ -356,7 +332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -366,20 +342,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "notify"
version = "4.0.12"
version = "4.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -390,6 +365,14 @@ dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "number_prefix"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "numtoa"
version = "0.1.0"
@@ -417,7 +400,7 @@ dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -477,7 +460,7 @@ dependencies = [
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -525,7 +508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -538,7 +521,7 @@ dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -579,18 +562,6 @@ dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.1.6"
@@ -603,14 +574,6 @@ dependencies = [
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.6"
@@ -629,14 +592,14 @@ dependencies = [
[[package]]
name = "rustlings"
version = "2.1.0"
version = "2.2.1"
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)",
"console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"indicatif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
"indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -806,7 +769,7 @@ version = "2.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -817,7 +780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.7"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -839,7 +802,7 @@ name = "winapi-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -857,7 +820,6 @@ dependencies = [
]
[metadata]
"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e"
@@ -866,11 +828,10 @@ dependencies = [
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum clicolors-control 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f84dec9bc083ce2503908cd305af98bd363da6f54bf8d4bf0ac14ee749ad5d1"
"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum console 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd48adf136733979b49e15bc3b4c43cc0d3c85ece7bd08e6daa414c6fcb13e6"
"checksum console 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2bf3720d3f3fc30b721ef1ae54e13af3264af4af39dc476a8de56a6ee1e2184b"
"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628"
"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd"
"checksum escargot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597"
@@ -882,13 +843,12 @@ dependencies = [
"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 indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe"
"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
@@ -900,8 +860,9 @@ dependencies = [
"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 notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
@@ -923,9 +884,7 @@ dependencies = [
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
@@ -953,7 +912,7 @@ dependencies = [
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"

View File

@@ -1,14 +1,14 @@
[package]
name = "rustlings"
version = "2.1.0"
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
version = "3.0.0"
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
edition = "2018"
[dependencies]
clap = "2.32.0"
indicatif = "0.9.0"
console = "0.6.2"
notify = "4.0.0"
indicatif = "0.10.3"
console = "0.7.7"
notify = "4.0.15"
toml = "0.4.10"
regex = "1.1.6"
serde = {version = "1.0.10", features = ["derive"]}

View File

@@ -1,6 +1,6 @@
![crab pet](https://i.imgur.com/LbZJgmm.gif)
# rustlings 🦀❤️
# rustlings 🦀❤️ [![Build status](https://badge.buildkite.com/7af93d81dc522c67a1ec8e33ff5705861b1cb36360b774807f.svg)](https://buildkite.com/mokou/rustlings)
Greetings and welcome to `rustlings`. This project contains small exercises to get you used to reading and writing Rust code. This includes reading and responding to compiler messages!
@@ -33,7 +33,13 @@ This will install Rustlings and give you access to the `rustlings` command. Run
## Windows
You can run:
First, set `ExecutionPolicy` to `RemoteSigned`:
```ps
Set-ExecutionPolicy RemoteSigned
```
Then, 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
@@ -48,7 +54,7 @@ Basically: Clone the repository, checkout to the latest tag, run `cargo install`
```bash
git clone https://github.com/rust-lang/rustlings
cd rustlings
git checkout tags/2.1.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
git checkout tags/3.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
cargo install --force --path .
```

5
buildkite.yml Normal file
View File

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

View File

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

View File

@@ -0,0 +1,15 @@
// clippy1.rs
// The Clippy tool is a collection of lints to analyze your code
// so you can catch common mistakes and improve your Rust code.
//
// Execute `rustlings hint clippy1` for hints :)
// I AM NOT DONE
fn main() {
let x = 1.2331f64;
let y = 1.2332f64;
if y != x {
println!("Success!");
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,80 @@
// The From trait is used for value-to-value conversions.
// If From is implemented correctly for a type, the Into trait should work conversely.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
#[derive(Debug)]
struct Person {
name: String,
age: usize,
}
// We implement the Default trait to use it as a fallback
// when the provided string is not convertible into a Person object
impl Default for Person {
fn default() -> Person {
Person {
name: String::from("John"),
age: 30,
}
}
}
// I AM NOT DONE
// Your task is to complete this implementation
// in order for the line `let p = Person::from("Mark,20")` to compile
// Please note that you'll need to parse the age component into a `usize`
// with something like `"4".parse::<usize>()`. The outcome of this needs to
// be handled appropriately.
//
// Steps:
// 1. If the length of the provided string is 0, then return the default of Person
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return the default of Person
// Otherwise, then return an instantiated Person onject with the results
impl From<&str> for Person {
fn from(s: &str) -> Person {
}
}
fn main() {
// Use the `from` function
let p1 = Person::from("Mark,20");
// Since From is implemented for Person, we should be able to use Into
let p2: Person = "Gerald,70".into();
println!("{:?}", p1);
println!("{:?}", p2);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
// Test that the default person is 30 year old John
let dp = Person::default();
assert_eq!(dp.name, "John");
assert_eq!(dp.age, 30);
}
#[test]
fn test_bad_convert() {
// Test that John is returned when bad string is provided
let p = Person::from("");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_good_convert() {
// Test that "Mark,20" works
let p = Person::from("Mark,20");
assert_eq!(p.name, "Mark");
assert_eq!(p.age, 20);
}
#[test]
fn test_bad_age() {
// Test that "Mark.twenty" will return the default person due to an error in parsing age
let p = Person::from("Mark,twenty");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
}

View File

@@ -0,0 +1,49 @@
// This does practically the same thing that TryFrom<&str> does.
// Additionally, upon implementing FromStr, you can use the `parse` method
// on strings to generate an object of the implementor type.
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
use std::str::FromStr;
#[derive(Debug)]
struct Person {
name: String,
age: usize,
}
// I AM NOT DONE
// Steps:
// 1. If the length of the provided string is 0, then return an error
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return an error
// Otherwise, then return a Result of a Person object
impl FromStr for Person {
type Err = String;
fn from_str(s: &str) -> Result<Person, Self::Err> {
}
}
fn main() {
let p = "Mark,20".parse::<Person>().unwrap();
println!("{:?}", p);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_input() {
assert!("".parse::<Person>().is_err());
}
#[test]
fn good_input() {
assert!("John,32".parse::<Person>().is_ok());
}
#[test]
#[should_panic]
fn missing_age() {
"John".parse::<Person>().unwrap();
}
}

View File

@@ -0,0 +1,71 @@
// TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
// Basically, this is the same as From. The main difference is that this should return a Result type
// instead of the target type itself.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
use std::convert::{TryInto, TryFrom};
#[derive(Debug)]
struct Person {
name: String,
age: usize,
}
// I AM NOT DONE
// Your task is to complete this implementation
// in order for the line `let p = Person::try_from("Mark,20")` to compile
// and return an Ok result of inner type Person.
// Please note that you'll need to parse the age component into a `usize`
// with something like `"4".parse::<usize>()`. The outcome of this needs to
// be handled appropriately.
//
// Steps:
// 1. If the length of the provided string is 0, then return an error
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return an error
// Otherwise, then return a Result of a Person object
impl TryFrom<&str> for Person {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
}
}
fn main() {
// Use the `from` function
let p1 = Person::try_from("Mark,20");
// Since From is implemented for Person, we should be able to use Into
let p2: Result<Person, _> = "Gerald,70".try_into();
println!("{:?}", p1);
println!("{:?}", p2);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bad_convert() {
// Test that John is returned when bad string is provided
let p = Person::try_from("");
assert!(p.is_err());
}
#[test]
fn test_good_convert() {
// Test that "Mark,20" works
let p = Person::try_from("Mark,20");
assert!(p.is_ok());
let p = p.unwrap();
assert_eq!(p.name, "Mark");
assert_eq!(p.age, 20);
}
#[test]
#[should_panic]
fn test_panic_empty_input() {
let p: Person = "".try_into().unwrap();
}
#[test]
#[should_panic]
fn test_panic_bad_age() {
let p = Person::try_from("Mark,twenty").unwrap();
}
}

View File

@@ -0,0 +1,17 @@
// Type casting in Rust is done via the usage of the `as` operator.
// Please note that the `as` operator is not only used when type casting.
// It also helps with renaming imports.
// I AM NOT DONE
// The goal is to make sure that the division does not fail to compile
fn average(values: &[f64]) -> f64 {
let total = values
.iter()
.fold(0.0, |a, b| a + b);
total / values.len()
}
fn main() {
let values = [3.5, 0.3, 13.0, 11.7];
println!("{}", average(&values));
}

View File

@@ -1,6 +1,8 @@
### Enums
Rust allows you to define a type called `enums` which allow you to enumerate possible values. In combination with enums, we have the concept of `pattern matching` in Rust, which makes it easy to run different code for different values of an enumeration. Enums, while available in many languages, Rust's enums are most similar to `algebraic data types` in functional languages, such as F#, OCaml, and Haskell.
Rust allows you to define types called "enums" which enumerate possible values.
Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
#### Book Sections

View File

@@ -2,7 +2,7 @@
// Make me compile! Execute `rustlings hint functions4` for hints :)
// This store is having a sale where if the price is an even number, you get
// 10 (money unit) off, but if it's an odd number, it's 3 (money unit) less.
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
// I AM NOT DONE

View File

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

View File

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

View File

@@ -0,0 +1,30 @@
// This powerful wrapper provides the ability to store a positive integer value.
// Rewrite it using generics so that it supports wrapping ANY type.
// I AM NOT DONE
struct Wrapper<u32> {
value: u32
}
impl<u32> Wrapper<u32> {
pub fn new(value: u32) -> Self {
Wrapper { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn store_u32_in_wrapper() {
assert_eq!(Wrapper::new(42).value, 42);
}
#[test]
fn store_str_in_wrapper() {
// TODO: Delete this assert and uncomment the one below once you have finished the exercise.
assert!(false);
// assert_eq!(Wrapper::new("Foo").value, "Foo");
}
}

View File

@@ -0,0 +1,46 @@
// An imaginary magical school has a new report card generation system written in rust!
// Currently the system only supports creating report cards where the student's grade
// is represented numerically (e.g. 1.0 -> 5.5). However, the school also issues alphabetical grades
// (A+ -> F-) and needs to be able to print both types of report card!
// Make the necessary code changes to support alphabetical report cards, thereby making the second
// test pass.
// I AM NOT DONE
pub struct ReportCard {
pub grade: f32,
pub student_name: String,
pub student_age: u8,
}
impl ReportCard {
pub fn print(&self) -> String {
format!("{} ({}) - achieved a grade of {}", &self.student_name, &self.student_age, &self.grade)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_numeric_report_card() {
let report_card = ReportCard {
grade: 2.1,
student_name: "Tom Wriggle".to_string(),
student_age: 12,
};
assert_eq!(report_card.print(), "Tom Wriggle (12) - achieved a grade of 2.1");
}
#[test]
fn generate_alphabetic_report_card() {
// TODO: Make sure to change the grade here after you finish the exercise.
let report_card = ReportCard {
grade: 2.1,
student_name: "Gary Plotter".to_string(),
student_age: 11,
};
assert_eq!(report_card.print(), "Gary Plotter (11) - achieved a grade of A+");
}
}

View File

@@ -0,0 +1,9 @@
### Option
#### Book Sections
To learn about Option<T>, check out these links:
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions)
- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@
// - Variables
// - Functions
// Mary is buying apples. One apple usually costs 2 dollars, but if you buy
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
// more than 40 at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the order amount. No hints this time!

View File

@@ -7,8 +7,17 @@
// I AM NOT DONE
fn main() {
if my_macro!("world!") != "Hello world!" {
panic!("Oh no! Wrong output!");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_my_macro_world() {
assert_eq!(my_macro!("world!"), "Hello world!");
}
#[test]
fn test_my_macro_goodbye() {
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
}
}

View File

@@ -1,7 +1,7 @@
// tests1.rs
// Tests are important to ensure that your code does what you think it should do.
// Tests can be run on this file with the following command:
// rustlings run --test exercises/tests/tests1.rs
// rustlings run tests1
// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Execute `rustlings hint tests1` for hints :)

View File

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

View File

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

View File

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

158
info.toml
View File

@@ -41,6 +41,20 @@ value. We can't print out something that isn't there; try giving x a value!
This is an error that can cause bugs that's very easy to make in any
programming language -- thankfully the Rust compiler has caught this for us!"""
[[exercises]]
name = "variables5"
path = "exercises/variables/variables5.rs"
mode = "compile"
hint = """
In variables3 we already learned how to make an immutable variable mutable
using a special keyword. Unfortunately this doesn't help us much in this exercise
because we want to assign a different typed value to an existing variable. Sometimes
you may also like to reuse existing variable names because you are just converting
values to different types like in this exercise.
Fortunately Rust has a powerful solution to this problem: 'Shadowing'!
You can read more about 'Shadowing' in the book's section 'Variables and Mutability'.
Try to solve this exercise afterwards using this technique."""
# IF
[[exercises]]
@@ -355,7 +369,7 @@ The way macros are written, it wants to see something between each
[[exercises]]
name = "test4"
path = "exercises/test4.rs"
mode = "compile"
mode = "test"
hint = "No hints this time ;)"
# MOVE SEMANTICS
@@ -497,14 +511,32 @@ https://doc.rust-lang.org/std/result/#results-must-be-used"""
[[exercises]]
name = "option1"
path = "exercises/error_handling/option1.rs"
mode = "test"
path = "exercises/option/option1.rs"
mode = "compile"
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!"""
Check out some functions of Option:
is_some
is_none
unwrap
and:
pattern matching
"""
[[exercises]]
name = "option2"
path = "exercises/option/option2.rs"
mode = "compile"
hint = """
check out:
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html
Remember that Options can be stacked in if let and while let.
For example: Some(Some(variable)) = variable2
"""
[[exercises]]
name = "result1"
@@ -515,6 +547,22 @@ hint = """
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 :)"""
# CLIPPY
[[exercises]]
name = "clippy1"
path = "exercises/clippy/clippy1.rs"
mode = "clippy"
hint = """
Floating point calculations are usually imprecise, so asking if two values are exactly equal is asking for trouble"""
[[exercises]]
name = "clippy2"
path = "exercises/clippy/clippy2.rs"
mode = "clippy"
hint = """
`for` loops over Option values are more clearly expressed as an `if let`"""
# STANDARD LIBRARY TYPES
[[exercises]]
@@ -572,6 +620,60 @@ 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."""
# TRAITS
[[exercises]]
name = "traits1"
path = "exercises/traits/traits1.rs"
mode = "test"
hint = """
A discussion about Traits in Rust can be found at:
https://doc.rust-lang.org/book/ch10-02-traits.html
"""
[[exercises]]
name = "traits2"
path = "exercises/traits/traits2.rs"
mode = "test"
hint = """
Notice how the trait takes ownership of 'self',and returns `Self'.
Try mutating the incoming string vector.
Vectors provide suitable methods for adding an element at the end. See
the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html"""
# Generics
[[exercises]]
name = "generics1"
path = "exercises/generics/generics1.rs"
mode = "compile"
hint = """
Vectors in rust make use of generics to create dynamically sized arrays of any type.
You need to tell the compiler what type we are pushing onto this vector."""
[[exercises]]
name = "generics2"
path = "exercises/generics/generics2.rs"
mode = "test"
hint = """
Think carefully about what we need to do here. Currently we are wrapping only values of
type 'u32'. Maybe we need to update the explicit references to this data type somehow?
"""
[[exercises]]
name = "generics3"
path = "exercises/generics/generics3.rs"
mode = "test"
hint = """
To find the best solution to this challenge you're going to need to think back to your
knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;"
This is definitely harder than the last two exercises! You need to think about not only making the
ReportCard struct generic, but also the correct property - you will need to change the implementation
of the struct slightly too...you can do it!
"""
# THREADS
[[exercises]]
@@ -610,3 +712,43 @@ answers and don't understand why they work and yours doesn't.
If you've learned from the sample solutions, I encourage you to come
back to this exercise and try it again in a few days to reinforce
what you've learned :)"""
# TYPE CONVERSIONS
[[exercises]]
name = "using_as"
path = "exercises/conversions/using_as.rs"
mode = "compile"
hint = """
Use the `as` operator to cast one of the operands in the last line of the
`average` function into the expected return type."""
[[exercises]]
name = "from_into"
path = "exercises/conversions/from_into.rs"
mode = "test"
hint = """
Follow the steps provided right before the `From` implementation"""
[[exercises]]
name = "try_from_into"
path = "exercises/conversions/try_from_into.rs"
mode = "test"
hint = """
Follow the steps provided right before the `From` implementation.
You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html"""
[[exercises]]
name = "as_ref_mut"
path = "exercises/conversions/as_ref_mut.rs"
mode = "test"
hint = """
Add AsRef<str> as a trait bound to the functions."""
[[exercises]]
name = "from_str"
path = "exercises/conversions/from_str.rs"
mode = "test"
hint = """
If you've already solved try_from_into.rs, then this is almost a copy-paste.
Otherwise, go ahead and solve try_from_into.rs first."""

View File

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

View File

@@ -7,7 +7,7 @@ if [ -x "$(command -v git)" ]
then
echo "SUCCESS: Git is installed"
else
echo "WARNING: Git does not seem to be installed."
echo "ERROR: Git does not seem to be installed."
echo "Please download Git using your package manager or over https://git-scm.com/!"
exit 1
fi
@@ -16,7 +16,7 @@ if [ -x "$(command -v rustc)" ]
then
echo "SUCCESS: Rust is installed"
else
echo "WARNING: Rust does not seem to be installed."
echo "ERROR: Rust does not seem to be installed."
echo "Please download Rust using https://rustup.rs!"
exit 1
fi
@@ -25,7 +25,7 @@ if [ -x "$(command -v cargo)" ]
then
echo "SUCCESS: Cargo is installed"
else
echo "WARNING: Cargo does not seem to be installed."
echo "ERROR: Cargo does not seem to be installed."
echo "Please download Rust and Cargo using https://rustup.rs!"
exit 1
fi
@@ -75,7 +75,7 @@ MinRustVersion=1.31
vercomp $RustVersion $MinRustVersion
if [ $? -eq 2 ]
then
echo "WARNING: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
echo "ERROR: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
echo "Please update Rust with 'rustup update'"
exit 1
else
@@ -87,6 +87,8 @@ echo "Cloning Rustlings at $Path..."
git clone -q https://github.com/rust-lang/rustlings $Path
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin"
echo "Checking out version $Version..."
cd $Path
git checkout -q tags/$Version
@@ -96,7 +98,16 @@ cargo install --force --path .
if ! [ -x "$(command -v rustlings)" ]
then
echo "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
echo "WARNING: Please check that you have '$CargoBin' in your PATH environment variable!"
fi
# Checking whether Clippy is installed.
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
Clippy=$(rustup component list | grep "clippy" | grep "installed")
if [ -z "$Clippy" ]
then
echo "Installing the 'cargo-clippy' executable..."
rustup component add clippy
fi
echo "All done! Run 'rustlings' to get started."

View File

@@ -1,14 +1,15 @@
use regex::Regex;
use serde::Deserialize;
use std::fmt::{self, Display, Formatter};
use std::fs::{remove_file, File};
use std::fs::{self, remove_file, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::{self, Command, Output};
use std::process::{self, Command};
const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];
const I_AM_DONE_REGEX: &str = r"(?m)^\s*///?\s*I\s+AM\s+NOT\s+DONE";
const CONTEXT: usize = 2;
const CLIPPY_CARGO_TOML_PATH: &str = "./exercises/clippy/Cargo.toml";
fn temp_file() -> String {
format!("./temp_{}", process::id())
@@ -19,6 +20,7 @@ fn temp_file() -> String {
pub enum Mode {
Compile,
Test,
Clippy,
}
#[derive(Deserialize)]
@@ -47,9 +49,34 @@ pub struct ContextLine {
pub important: bool,
}
pub struct CompiledExercise<'a> {
exercise: &'a Exercise,
_handle: FileHandle,
}
impl<'a> CompiledExercise<'a> {
pub fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
self.exercise.run()
}
}
#[derive(Debug)]
pub struct ExerciseOutput {
pub stdout: String,
pub stderr: String,
}
struct FileHandle;
impl Drop for FileHandle {
fn drop(&mut self) {
clean();
}
}
impl Exercise {
pub fn compile(&self) -> Output {
match self.mode {
pub fn compile(&self) -> Result<CompiledExercise, ExerciseOutput> {
let cmd = match self.mode {
Mode::Compile => Command::new("rustc")
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
@@ -58,18 +85,75 @@ impl Exercise {
.args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output(),
Mode::Clippy => {
let cargo_toml = format!(
r#"[package]
name = "{}"
version = "0.0.1"
edition = "2018"
[[bin]]
name = "{}"
path = "{}.rs""#,
self.name, self.name, self.name
);
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml)
.expect("Failed to write 📎 Clippy 📎 Cargo.toml file.");
// To support the ability to run the clipy exercises, build
// an executable, in addition to running clippy. With a
// compilation failure, this would silently fail. But we expect
// clippy to reflect the same failure while compiling later.
Command::new("rustc")
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output()
.expect("Failed to compile!");
// Due to an issue with Clippy, a cargo clean is required to catch all lints.
// See https://github.com/rust-lang/rust-clippy/issues/2604
// This is already fixed on master branch. See this issue to track merging into Cargo:
// https://github.com/rust-lang/rust-clippy/issues/3837
Command::new("cargo")
.args(&["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS)
.output()
.expect("Failed to run 'cargo clean'");
Command::new("cargo")
.args(&["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS)
.args(&["--", "-D", "warnings"])
.output()
}
}
.expect("Failed to run 'compile' command.");
if cmd.status.success() {
Ok(CompiledExercise {
exercise: &self,
_handle: FileHandle,
})
} else {
clean();
Err(ExerciseOutput {
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
})
}
.expect("Failed to run 'compile' command.")
}
pub fn run(&self) -> Output {
Command::new(&temp_file())
fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
let cmd = Command::new(&temp_file())
.output()
.expect("Failed to run 'run' command")
}
.expect("Failed to run 'run' command");
pub fn clean(&self) {
let _ignored = remove_file(&temp_file());
let output = ExerciseOutput {
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
};
if cmd.status.success() {
Ok(output)
} else {
Err(output)
}
}
pub fn state(&self) -> State {
@@ -121,6 +205,10 @@ impl Display for Exercise {
}
}
fn clean() {
let _ignored = remove_file(&temp_file());
}
#[cfg(test)]
mod test {
use super::*;
@@ -131,11 +219,12 @@ mod test {
File::create(&temp_file()).unwrap();
let exercise = Exercise {
name: String::from("example"),
path: PathBuf::from("example.rs"),
mode: Mode::Test,
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),
mode: Mode::Compile,
hint: String::from(""),
};
exercise.clean();
let compiled = exercise.compile().unwrap();
drop(compiled);
assert!(!Path::new(&temp_file()).exists());
}

View File

@@ -2,6 +2,7 @@ use crate::exercise::{Exercise, ExerciseList};
use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use console::Emoji;
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
@@ -14,6 +15,9 @@ use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
#[macro_use]
mod ui;
mod exercise;
mod run;
mod verify;
@@ -102,7 +106,21 @@ fn main() {
}
if matches.subcommand_matches("watch").is_some() {
watch(&exercises).unwrap();
if watch(&exercises).is_ok() {
println!(
"{emoji} All exercises completed! {emoji}",
emoji = Emoji("🎉", "")
);
println!("");
println!("We hope you enjoyed learning about the various aspects of Rust!");
println!(
"If you noticed any issues, please don't hesitate to report them to our repo."
);
println!("You can also contribute your own exercises to help the greater community!");
println!("");
println!("Before reporting an issue or contributing, please read our guidelines:");
println!("https://github.com/rust-lang/rustlings/blob/master/CONTRIBUTING.md");
}
}
if matches.subcommand_name().is_none() {
@@ -144,10 +162,12 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
clear_screen();
let verify_result = verify(exercises.iter());
let to_owned_hint = |t: &Exercise| t.hint.to_owned();
let failed_exercise_hint = Arc::new(Mutex::new(verify_result.map_err(to_owned_hint).err()));
let failed_exercise_hint = match verify(exercises.iter()) {
Ok(_) => return Ok(()),
Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))),
};
spawn_watch_shell(&failed_exercise_hint);
loop {
match rx.recv() {
@@ -159,9 +179,13 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
.iter()
.skip_while(|e| !filepath.ends_with(&e.path));
clear_screen();
let verify_result = verify(pending_exercises);
let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap();
*failed_exercise_hint = verify_result.map_err(to_owned_hint).err();
match verify(pending_exercises) {
Ok(_) => return Ok(()),
Err(exercise) => {
let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap();
*failed_exercise_hint = Some(to_owned_hint(exercise));
}
}
}
}
_ => {}

View File

@@ -1,52 +1,51 @@
use crate::exercise::{Exercise, Mode};
use crate::verify::test;
use console::{style, Emoji};
use indicatif::ProgressBar;
pub fn run(exercise: &Exercise) -> Result<(), ()> {
match exercise.mode {
Mode::Test => test(exercise)?,
Mode::Compile => compile_and_run(exercise)?,
Mode::Clippy => compile_and_run(exercise)?,
}
Ok(())
}
pub fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compilecmd = exercise.compile();
let compilation_result = exercise.compile();
let compilation = match compilation_result {
Ok(compilation) => compilation,
Err(output) => {
progress_bar.finish_and_clear();
warn!(
"Compilation of {} failed!, Compiler error message:\n",
exercise
);
println!("{}", output.stderr);
return Err(());
}
};
progress_bar.set_message(format!("Running {}...", exercise).as_str());
if compilecmd.status.success() {
let runcmd = exercise.run();
progress_bar.finish_and_clear();
let result = compilation.run();
progress_bar.finish_and_clear();
if runcmd.status.success() {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
let formatstr = format!("{} Successfully ran {}", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
exercise.clean();
match result {
Ok(output) => {
println!("{}", output.stdout);
success!("Successfully ran {}", exercise);
Ok(())
} else {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
}
Err(output) => {
println!("{}", output.stdout);
println!("{}", output.stderr);
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
println!("{}", style(formatstr).red());
exercise.clean();
warn!("Ran {} with errors", exercise);
Err(())
}
} else {
progress_bar.finish_and_clear();
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
exercise.clean();
Err(())
}
}

23
src/ui.rs Normal file
View File

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

View File

@@ -1,12 +1,13 @@
use crate::exercise::{Exercise, Mode, State};
use console::{style, Emoji};
use crate::exercise::{CompiledExercise, Exercise, Mode, State};
use console::style;
use indicatif::ProgressBar;
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), &'a Exercise> {
for exercise in start_at {
let compile_result = match exercise.mode {
Mode::Test => compile_and_test_interactively(&exercise),
Mode::Compile => compile_only(&exercise),
Mode::Test => compile_and_test(&exercise, RunMode::Interactive),
Mode::Compile => compile_and_run_interactively(&exercise),
Mode::Clippy => compile_only(&exercise),
};
if !compile_result.unwrap_or(false) {
return Err(exercise);
@@ -15,8 +16,13 @@ pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<()
Ok(())
}
enum RunMode {
Interactive,
NonInteractive,
}
pub fn test(exercise: &Exercise) -> Result<(), ()> {
compile_and_test(exercise, true)?;
compile_and_test(exercise, RunMode::NonInteractive)?;
Ok(())
}
@@ -24,73 +30,89 @@ fn compile_only(exercise: &Exercise) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compile_output = exercise.compile();
let _ = compile(&exercise, &progress_bar)?;
progress_bar.finish_and_clear();
if compile_output.status.success() {
let formatstr = format!("{} Successfully compiled {}!", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
exercise.clean();
Ok(prompt_for_completion(&exercise))
} else {
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
exercise.clean();
Err(())
}
success!("Successfully compiled {}!", exercise);
Ok(prompt_for_completion(&exercise, None))
}
fn compile_and_test_interactively(exercise: &Exercise) -> Result<bool, ()> {
compile_and_test(exercise, false)
fn compile_and_run_interactively(exercise: &Exercise) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compilation = compile(&exercise, &progress_bar)?;
progress_bar.set_message(format!("Running {}...", exercise).as_str());
let result = compilation.run();
progress_bar.finish_and_clear();
let output = match result {
Ok(output) => output,
Err(output) => {
warn!("Ran {} with errors", exercise);
println!("{}", output.stdout);
return Err(());
}
};
success!("Successfully ran {}!", exercise);
Ok(prompt_for_completion(&exercise, Some(output.stdout)))
}
fn compile_and_test(exercise: &Exercise, skip_prompt: bool) -> Result<bool, ()> {
fn compile_and_test(exercise: &Exercise, run_mode: RunMode) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compile_output = exercise.compile();
if compile_output.status.success() {
progress_bar.set_message(format!("Running {}...", exercise).as_str());
let compilation = compile(exercise, &progress_bar)?;
let result = compilation.run();
progress_bar.finish_and_clear();
let runcmd = exercise.run();
progress_bar.finish_and_clear();
if runcmd.status.success() {
let formatstr = format!("{} Successfully tested {}!", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
exercise.clean();
Ok(skip_prompt || prompt_for_completion(exercise))
} else {
let formatstr = format!(
"{} Testing of {} failed! Please try again. Here's the output:",
Emoji("⚠️ ", "!"),
match result {
Ok(_) => {
success!("Successfully tested {}", &exercise);
if let RunMode::Interactive = run_mode {
Ok(prompt_for_completion(&exercise, None))
} else {
Ok(true)
}
}
Err(output) => {
warn!(
"Testing of {} failed! Please try again. Here's the output:",
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
exercise.clean();
println!("{}", output.stdout);
Err(())
}
} else {
progress_bar.finish_and_clear();
let formatstr = format!(
"{} Compiling of {} failed! Please try again. Here's the output:",
Emoji("⚠️ ", "!"),
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
exercise.clean();
Err(())
}
}
fn prompt_for_completion(exercise: &Exercise) -> bool {
fn compile<'a, 'b>(
exercise: &'a Exercise,
progress_bar: &'b ProgressBar,
) -> Result<CompiledExercise<'a>, ()> {
let compilation_result = exercise.compile();
match compilation_result {
Ok(compilation) => Ok(compilation),
Err(output) => {
progress_bar.finish_and_clear();
warn!(
"Compiling of {} failed! Please try again. Here's the output:",
exercise
);
println!("{}", output.stderr);
Err(())
}
}
}
fn prompt_for_completion(exercise: &Exercise, prompt_output: Option<String>) -> bool {
let context = match exercise.state() {
State::Done => return true,
State::Pending(context) => context,
@@ -99,11 +121,21 @@ fn prompt_for_completion(exercise: &Exercise) -> bool {
let success_msg = match exercise.mode {
Mode::Compile => "The code is compiling!",
Mode::Test => "The code is compiling, and the tests pass!",
Mode::Clippy => "The code is compiling, and 📎 Clippy 📎 is happy!",
};
println!("");
println!("🎉 🎉 {} 🎉 🎉", success_msg);
println!("");
if let Some(output) = prompt_output {
println!("Output:");
println!("{}", separator());
println!("{}", output);
println!("{}", separator());
println!("");
}
println!("You can keep working on this exercise,");
println!(
"or jump into the next one by removing the {} comment:",
@@ -127,3 +159,7 @@ fn prompt_for_completion(exercise: &Exercise) -> bool {
false
}
fn separator() -> console::StyledObject<&'static str> {
style("====================").bold()
}

View File

@@ -31,7 +31,7 @@ fn verify_all_success() {
}
#[test]
fn verify_all_failure() {
fn verify_fails_if_some_fails() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("v")