Compare commits

..

No commits in common. "main" and "all-contributors/add-novanish" have entirely different histories.

45 changed files with 405 additions and 1129 deletions

View File

@ -2217,222 +2217,6 @@
"contributions": [ "contributions": [
"content" "content"
] ]
},
{
"login": "vnprc",
"name": "vnprc",
"avatar_url": "https://avatars.githubusercontent.com/u/9425366?v=4",
"profile": "https://github.com/vnprc",
"contributions": [
"content"
]
},
{
"login": "jrcarl624",
"name": "Joshua Carlson",
"avatar_url": "https://avatars.githubusercontent.com/u/61999256?v=4",
"profile": "http://androecia.net",
"contributions": [
"content"
]
},
{
"login": "johnDeSilencio",
"name": "Nicholas R. Smith",
"avatar_url": "https://avatars.githubusercontent.com/u/20136554?v=4",
"profile": "https://johndesilencio.me",
"contributions": [
"code"
]
},
{
"login": "alexfertel",
"name": "Alexander González",
"avatar_url": "https://avatars.githubusercontent.com/u/22298999?v=4",
"profile": "https://alexfertel.me",
"contributions": [
"content"
]
},
{
"login": "softarn",
"name": "Marcus Höjvall",
"avatar_url": "https://avatars.githubusercontent.com/u/517619?v=4",
"profile": "https://github.com/softarn",
"contributions": [
"content"
]
},
{
"login": "barlevalon",
"name": "Alon Hearter",
"avatar_url": "https://avatars.githubusercontent.com/u/3397911?v=4",
"profile": "https://github.com/barlevalon",
"contributions": [
"content"
]
},
{
"login": "shirts",
"name": "shirts",
"avatar_url": "https://avatars.githubusercontent.com/u/4952151?v=4",
"profile": "https://github.com/shirts",
"contributions": [
"content"
]
},
{
"login": "eLVas",
"name": "Ivan Vasiunyk",
"avatar_url": "https://avatars.githubusercontent.com/u/6797156?v=4",
"profile": "https://github.com/eLVas",
"contributions": [
"content"
]
},
{
"login": "mo8it",
"name": "Mo",
"avatar_url": "https://avatars.githubusercontent.com/u/76752051?v=4",
"profile": "https://mo8it.com",
"contributions": [
"code"
]
},
{
"login": "x10an14",
"name": "x10an14",
"avatar_url": "https://avatars.githubusercontent.com/u/710608?v=4",
"profile": "https://github.com/x10an14",
"contributions": [
"infra"
]
},
{
"login": "gabay",
"name": "Roi Gabay",
"avatar_url": "https://avatars.githubusercontent.com/u/5773610?v=4",
"profile": "https://github.com/gabay",
"contributions": [
"content"
]
},
{
"login": "mkovaxx",
"name": "Máté Kovács",
"avatar_url": "https://avatars.githubusercontent.com/u/481354?v=4",
"profile": "https://github.com/mkovaxx",
"contributions": [
"content"
]
},
{
"login": "szabgab",
"name": "Gábor Szabó",
"avatar_url": "https://avatars.githubusercontent.com/u/48833?v=4",
"profile": "https://szabgab.com/",
"contributions": [
"content"
]
},
{
"login": "yamila-moreno",
"name": "Yamila Moreno",
"avatar_url": "https://avatars.githubusercontent.com/u/3340793?v=4",
"profile": "https://moduslaborandi.net",
"contributions": [
"content"
]
},
{
"login": "willhack",
"name": "Will Hack",
"avatar_url": "https://avatars.githubusercontent.com/u/18036720?v=4",
"profile": "https://github.com/willhack",
"contributions": [
"content"
]
},
{
"login": "bean5",
"name": "Michael",
"avatar_url": "https://avatars.githubusercontent.com/u/2052646?v=4",
"profile": "http://cancompute.tech",
"contributions": [
"content"
]
},
{
"login": "pksadiq",
"name": "Mohammed Sadiq",
"avatar_url": "https://avatars.githubusercontent.com/u/1289514?v=4",
"profile": "https://www.sadiqpk.org",
"contributions": [
"content"
]
},
{
"login": "Jak-Ch-ll",
"name": "Jakob",
"avatar_url": "https://avatars.githubusercontent.com/u/56225668?v=4",
"profile": "https://github.com/Jak-Ch-ll",
"contributions": [
"content"
]
},
{
"login": "ob",
"name": "Oscar Bonilla",
"avatar_url": "https://avatars.githubusercontent.com/u/4950?v=4",
"profile": "http://oscarbonilla.com",
"contributions": [
"content"
]
},
{
"login": "husjon",
"name": "Jon Erling Hustadnes",
"avatar_url": "https://avatars.githubusercontent.com/u/554229?v=4",
"profile": "https://github.com/husjon",
"contributions": [
"content"
]
},
{
"login": "CobaltCause",
"name": "Charles Hall",
"avatar_url": "https://avatars.githubusercontent.com/u/7003738?v=4",
"profile": "https://github.com/CobaltCause",
"contributions": [
"infra"
]
},
{
"login": "krmpotic",
"name": "Luka Krmpotić",
"avatar_url": "https://avatars.githubusercontent.com/u/10350645?v=4",
"profile": "https://github.com/krmpotic",
"contributions": [
"content"
]
},
{
"login": "jurglic",
"name": "Jurglic",
"avatar_url": "https://avatars.githubusercontent.com/u/112600?v=4",
"profile": "https://github.com/jurglic",
"contributions": [
"content"
]
},
{
"login": "OfirLauber",
"name": "Ofir Lauber",
"avatar_url": "https://avatars.githubusercontent.com/u/5631030?v=4",
"profile": "https://github.com/OfirLauber",
"contributions": [
"content"
]
} }
], ],
"contributorsPerLine": 8, "contributorsPerLine": 8,

4
.envrc
View File

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Automatically Load nix devShell w/dotenv
use flake

18
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: Lint
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: DavidAnson/markdownlint-cli2-action@v9
with:
globs: "exercises/**/*.md"

View File

@ -10,28 +10,13 @@ env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
jobs: jobs:
fmt: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable - name: Fetch & maybe update Cargo.lock
with: run: cargo fetch --locked
components: rustfmt - name: Build
- uses: DavidAnson/markdownlint-cli2-action@v9 run: cargo build --verbose
with: - name: Run tests
globs: "exercises/**/*.md" run: cargo test --verbose
- name: Run cargo fmt
run: |
cargo fmt --all -- --check
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- uses: swatinem/rust-cache@v2
- name: Run cargo test
run: |
cargo test

View File

@ -1,88 +0,0 @@
# Workflow to build your docs with oranda (and mdbook)
# and deploy them to Github Pages
name: Web
# We're going to push to the gh-pages branch, so we need that permission
permissions:
contents: write
# What situations do we want to build docs in?
# All of these work independently and can be removed / commented out
# if you don't want oranda/mdbook running in that situation
on:
# Check that a PR didn't break docs!
#
# Note that the "Deploy to Github Pages" step won't run in this mode,
# so this won't have any side-effects. But it will tell you if a PR
# completely broke oranda/mdbook. Sadly we don't provide previews (yet)!
pull_request:
# Whenever something gets pushed to main, update the docs!
# This is great for getting docs changes live without cutting a full release.
#
# Note that if you're using cargo-dist, this will "race" the Release workflow
# that actually builds the Github Release that oranda tries to read (and
# this will almost certainly complete first). As a result you will publish
# docs for the latest commit but the oranda landing page won't know about
# the latest release. The workflow_run trigger below will properly wait for
# cargo-dist, and so this half-published state will only last for ~10 minutes.
#
# If you only want docs to update with releases, disable this, or change it to
# a "release" branch. You can, of course, also manually trigger a workflow run
# when you want the docs to update.
push:
branches:
- main
# Whenever a workflow called "Release" completes, update the docs!
#
# If you're using cargo-dist, this is recommended, as it will ensure that
# oranda always sees the latest release right when it's available. Note
# however that Github's UI is wonky when you use workflow_run, and won't
# show this workflow as part of any commit. You have to go to the "actions"
# tab for your repo to see this one running (the gh-pages deploy will also
# only show up there).
workflow_run:
workflows: [ "Release" ]
types:
- completed
# Alright, let's do it!
jobs:
web:
name: Build and deploy site and docs
runs-on: ubuntu-latest
steps:
# Setup
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: swatinem/rust-cache@v2
# If you use any mdbook plugins, here's the place to install them!
# Install and run oranda (and mdbook)
# This will write all output to ./public/ (including copying mdbook's output to there)
- name: Install and run oranda
run: |
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/oranda/releases/download/v0.3.1/oranda-installer.sh | sh
oranda build
# Deploy to our gh-pages branch (creating it if it doesn't exist)
# the "public" dir that oranda made above will become the root dir
# of this branch.
#
# Note that once the gh-pages branch exists, you must
# go into repo's settings > pages and set "deploy from branch: gh-pages"
# the other defaults work fine.
- name: Deploy to Github Pages
uses: JamesIves/github-pages-deploy-action@v4.4.1
# ONLY if we're on main (so no PRs or feature branches allowed!)
if: ${{ github.ref == 'refs/heads/main' }}
with:
branch: gh-pages
# Gotta tell the action where to find oranda's output
folder: public
token: ${{ secrets.GITHUB_TOKEN }}
single-commit: true

1
.gitignore vendored
View File

@ -12,7 +12,6 @@ rust-project.json
*.iml *.iml
*.o *.o
public/ public/
.direnv/
# Local Netlify folder # Local Netlify folder
.netlify .netlify

View File

@ -314,36 +314,6 @@ authors.
<td align="center" valign="top" width="12.5%"><a href="https://robertfry.xyz"><img src="https://avatars.githubusercontent.com/u/43712054?v=4?s=100" width="100px;" alt="Robert Fry"/><br /><sub><b>Robert Fry</b></sub></a><br /><a href="#content-robertefry" title="Content">🖋</a></td> <td align="center" valign="top" width="12.5%"><a href="https://robertfry.xyz"><img src="https://avatars.githubusercontent.com/u/43712054?v=4?s=100" width="100px;" alt="Robert Fry"/><br /><sub><b>Robert Fry</b></sub></a><br /><a href="#content-robertefry" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tajo48"><img src="https://avatars.githubusercontent.com/u/55502906?v=4?s=100" width="100px;" alt="tajo48"/><br /><sub><b>tajo48</b></sub></a><br /><a href="#content-tajo48" title="Content">🖋</a></td> <td align="center" valign="top" width="12.5%"><a href="https://github.com/tajo48"><img src="https://avatars.githubusercontent.com/u/55502906?v=4?s=100" width="100px;" alt="tajo48"/><br /><sub><b>tajo48</b></sub></a><br /><a href="#content-tajo48" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://anishchhetri.com.np"><img src="https://avatars.githubusercontent.com/u/98446102?v=4?s=100" width="100px;" alt="Anish"/><br /><sub><b>Anish</b></sub></a><br /><a href="#content-novanish" title="Content">🖋</a></td> <td align="center" valign="top" width="12.5%"><a href="https://anishchhetri.com.np"><img src="https://avatars.githubusercontent.com/u/98446102?v=4?s=100" width="100px;" alt="Anish"/><br /><sub><b>Anish</b></sub></a><br /><a href="#content-novanish" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/vnprc"><img src="https://avatars.githubusercontent.com/u/9425366?v=4?s=100" width="100px;" alt="vnprc"/><br /><sub><b>vnprc</b></sub></a><br /><a href="#content-vnprc" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://androecia.net"><img src="https://avatars.githubusercontent.com/u/61999256?v=4?s=100" width="100px;" alt="Joshua Carlson"/><br /><sub><b>Joshua Carlson</b></sub></a><br /><a href="#content-jrcarl624" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://johndesilencio.me"><img src="https://avatars.githubusercontent.com/u/20136554?v=4?s=100" width="100px;" alt="Nicholas R. Smith"/><br /><sub><b>Nicholas R. Smith</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=johnDeSilencio" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://alexfertel.me"><img src="https://avatars.githubusercontent.com/u/22298999?v=4?s=100" width="100px;" alt="Alexander González"/><br /><sub><b>Alexander González</b></sub></a><br /><a href="#content-alexfertel" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/softarn"><img src="https://avatars.githubusercontent.com/u/517619?v=4?s=100" width="100px;" alt="Marcus Höjvall"/><br /><sub><b>Marcus Höjvall</b></sub></a><br /><a href="#content-softarn" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/barlevalon"><img src="https://avatars.githubusercontent.com/u/3397911?v=4?s=100" width="100px;" alt="Alon Hearter"/><br /><sub><b>Alon Hearter</b></sub></a><br /><a href="#content-barlevalon" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/shirts"><img src="https://avatars.githubusercontent.com/u/4952151?v=4?s=100" width="100px;" alt="shirts"/><br /><sub><b>shirts</b></sub></a><br /><a href="#content-shirts" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/eLVas"><img src="https://avatars.githubusercontent.com/u/6797156?v=4?s=100" width="100px;" alt="Ivan Vasiunyk"/><br /><sub><b>Ivan Vasiunyk</b></sub></a><br /><a href="#content-eLVas" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://mo8it.com"><img src="https://avatars.githubusercontent.com/u/76752051?v=4?s=100" width="100px;" alt="Mo"/><br /><sub><b>Mo</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=mo8it" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/x10an14"><img src="https://avatars.githubusercontent.com/u/710608?v=4?s=100" width="100px;" alt="x10an14"/><br /><sub><b>x10an14</b></sub></a><br /><a href="#infra-x10an14" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/gabay"><img src="https://avatars.githubusercontent.com/u/5773610?v=4?s=100" width="100px;" alt="Roi Gabay"/><br /><sub><b>Roi Gabay</b></sub></a><br /><a href="#content-gabay" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/mkovaxx"><img src="https://avatars.githubusercontent.com/u/481354?v=4?s=100" width="100px;" alt="Máté Kovács"/><br /><sub><b>Máté Kovács</b></sub></a><br /><a href="#content-mkovaxx" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://szabgab.com/"><img src="https://avatars.githubusercontent.com/u/48833?v=4?s=100" width="100px;" alt="Gábor Szabó"/><br /><sub><b>Gábor Szabó</b></sub></a><br /><a href="#content-szabgab" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://moduslaborandi.net"><img src="https://avatars.githubusercontent.com/u/3340793?v=4?s=100" width="100px;" alt="Yamila Moreno"/><br /><sub><b>Yamila Moreno</b></sub></a><br /><a href="#content-yamila-moreno" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/willhack"><img src="https://avatars.githubusercontent.com/u/18036720?v=4?s=100" width="100px;" alt="Will Hack"/><br /><sub><b>Will Hack</b></sub></a><br /><a href="#content-willhack" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://cancompute.tech"><img src="https://avatars.githubusercontent.com/u/2052646?v=4?s=100" width="100px;" alt="Michael"/><br /><sub><b>Michael</b></sub></a><br /><a href="#content-bean5" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.sadiqpk.org"><img src="https://avatars.githubusercontent.com/u/1289514?v=4?s=100" width="100px;" alt="Mohammed Sadiq"/><br /><sub><b>Mohammed Sadiq</b></sub></a><br /><a href="#content-pksadiq" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Jak-Ch-ll"><img src="https://avatars.githubusercontent.com/u/56225668?v=4?s=100" width="100px;" alt="Jakob"/><br /><sub><b>Jakob</b></sub></a><br /><a href="#content-Jak-Ch-ll" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://oscarbonilla.com"><img src="https://avatars.githubusercontent.com/u/4950?v=4?s=100" width="100px;" alt="Oscar Bonilla"/><br /><sub><b>Oscar Bonilla</b></sub></a><br /><a href="#content-ob" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/husjon"><img src="https://avatars.githubusercontent.com/u/554229?v=4?s=100" width="100px;" alt="Jon Erling Hustadnes"/><br /><sub><b>Jon Erling Hustadnes</b></sub></a><br /><a href="#content-husjon" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/CobaltCause"><img src="https://avatars.githubusercontent.com/u/7003738?v=4?s=100" width="100px;" alt="Charles Hall"/><br /><sub><b>Charles Hall</b></sub></a><br /><a href="#infra-CobaltCause" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/krmpotic"><img src="https://avatars.githubusercontent.com/u/10350645?v=4?s=100" width="100px;" alt="Luka Krmpotić"/><br /><sub><b>Luka Krmpotić</b></sub></a><br /><a href="#content-krmpotic" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jurglic"><img src="https://avatars.githubusercontent.com/u/112600?v=4?s=100" width="100px;" alt="Jurglic"/><br /><sub><b>Jurglic</b></sub></a><br /><a href="#content-jurglic" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/OfirLauber"><img src="https://avatars.githubusercontent.com/u/5631030?v=4?s=100" width="100px;" alt="Ofir Lauber"/><br /><sub><b>Ofir Lauber</b></sub></a><br /><a href="#content-OfirLauber" title="Content">🖋</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -1,59 +1,3 @@
<a name="5.6.1"></a>
## 5.6.1 (2023-09-18)
#### Changed
- Converted all exercises with assertions to test mode.
#### Fixed
- `cow1`: Reverted regression introduced by calling `to_mut` where it
shouldn't have been called, and clarified comment.
- `primitive_types3`: Require at least an array of 100 elements.
- Removed hint comments when no hint exists for the exercise.
- `as_ref_mut`: Fixed a typo in a test function name.
- `enums3`: Fixed formatting with `rustfmt`.
<a name="5.6.0"></a>
## 5.6.0 (2023-09-04)
#### Added
- New exercise: `if3`, teaching the user about `if let` statements.
- `hashmaps2`: Added an extra test function to check if the amount of fruits is higher than zero.
- `enums3`: Added a test for `Message`.
- `if1`: Added a test case to check equal values.
- `if3`: Added a note specifying that there are no test changes needed.
#### Changed
- Swapped the order of threads and smart pointer exercises.
- Rewrote the CLI to use `clap` - it's matured much since we switched to `argh` :)
- `structs3`: Switched from i32 to u32.
- `move_semantics`: Switched 1-4 to tests, and rewrote them to be way simpler, while still teaching about the same
concepts.
#### Fixed
- `iterators5`:
- Removed an outdated part of the hint.
- Renamed variables to use snake_case.
- `vecs2`: Updated the hint to reference the renamed loop variable.
- `enums3`: Changed message string in test so that it gets properly tested.
- `strings2`: Corrected line number in hint, then removed it (this both happened as part of this release cycle).
- `primitive_types4`: Updated hint to the correct ending index.
- `quiz1`: Removed duplicated sentence from exercise comments.
- `errors4`: Improved comment.
- `from_into`: Fixed test values.
- `cow1`: Added `.to_mut()` to distinguish from the previous test case.
- `threads2`: Updated hint text to reference the correct book heading.
#### Housekeeping
- Cleaned up the explanation paragraphs at the start of each exercise.
- Lots of Nix housekeeping that I don't feel qualified to write about!
- Improved CI workflows, we're now testing on multiple platforms at once.
<a name="5.5.1"></a> <a name="5.5.1"></a>
## 5.5.1 (2023-05-17) ## 5.5.1 (2023-05-17)

398
Cargo.lock generated
View File

@ -12,66 +12,43 @@ dependencies = [
] ]
[[package]] [[package]]
name = "anstream" name = "argh"
version = "0.5.0" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e"
dependencies = [ dependencies = [
"anstyle", "argh_derive",
"anstyle-parse", "argh_shared",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
] ]
[[package]] [[package]]
name = "anstyle" name = "argh_derive"
version = "1.0.3" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [ dependencies = [
"utf8parse", "argh_shared",
"proc-macro2",
"quote",
"syn 1.0.109",
] ]
[[package]] [[package]]
name = "anstyle-query" name = "argh_shared"
version = "1.0.0" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "anstyle-wincon"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "2.0.12" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" checksum = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e"
dependencies = [ dependencies = [
"anstyle", "escargot",
"bstr",
"doc-comment",
"predicates", "predicates",
"predicates-core", "predicates-core",
"predicates-tree", "predicates-tree",
"wait-timeout",
] ]
[[package]] [[package]]
@ -86,17 +63,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.10" version = "0.1.10"
@ -109,52 +75,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.5" version = "0.15.5"
@ -169,22 +89,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "difflib" name = "difference"
version = "0.4.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "encode_unicode" name = "encode_unicode"
@ -193,10 +101,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]] [[package]]
name = "equivalent" name = "escargot"
version = "1.0.1" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597"
dependencies = [
"lazy_static",
"log",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "filetime" name = "filetime"
@ -212,9 +126,9 @@ dependencies = [
[[package]] [[package]]
name = "float-cmp" name = "float-cmp"
version = "0.9.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
dependencies = [ dependencies = [
"num-traits", "num-traits",
] ]
@ -260,18 +174,6 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "home" name = "home"
version = "0.5.4" version = "0.5.4"
@ -281,27 +183,16 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "indexmap"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]] [[package]]
name = "indicatif" name = "indicatif"
version = "0.17.6" version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b"
dependencies = [ dependencies = [
"console", "console",
"instant", "lazy_static",
"number_prefix", "number_prefix",
"portable-atomic", "regex",
"unicode-width",
] ]
[[package]] [[package]]
@ -324,15 +215,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
[[package]] [[package]]
name = "iovec" name = "iovec"
version = "0.1.4" version = "0.1.4"
@ -342,15 +224,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.6" version = "1.0.6"
@ -396,9 +269,9 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.6.3" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "mio" name = "mio"
@ -493,22 +366,14 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "portable-atomic"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b"
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "3.0.3" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df"
dependencies = [ dependencies = [
"anstyle", "difference",
"difflib",
"float-cmp", "float-cmp",
"itertools",
"normalize-line-endings", "normalize-line-endings",
"predicates-core", "predicates-core",
"regex", "regex",
@ -568,12 +433,6 @@ dependencies = [
"regex-syntax", "regex-syntax",
] ]
[[package]]
name = "regex-automata"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.29" version = "0.6.29"
@ -582,10 +441,10 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "rustlings" name = "rustlings"
version = "5.6.1" version = "5.5.1"
dependencies = [ dependencies = [
"argh",
"assert_cmd", "assert_cmd",
"clap",
"console", "console",
"glob", "glob",
"home", "home",
@ -630,7 +489,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.8",
] ]
[[package]] [[package]]
@ -644,15 +503,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.8" version = "0.4.8"
@ -663,10 +513,15 @@ dependencies = [
] ]
[[package]] [[package]]
name = "strsim" name = "syn"
version = "0.10.0" version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "syn" name = "syn"
@ -687,36 +542,11 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.7.8" version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
] ]
[[package]] [[package]]
@ -731,21 +561,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.3" version = "2.3.3"
@ -805,13 +620,13 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm 0.42.2", "windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.2", "windows_aarch64_msvc",
"windows_i686_gnu 0.42.2", "windows_i686_gnu",
"windows_i686_msvc 0.42.2", "windows_i686_msvc",
"windows_x86_64_gnu 0.42.2", "windows_x86_64_gnu",
"windows_x86_64_gnullvm 0.42.2", "windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.2", "windows_x86_64_msvc",
] ]
[[package]] [[package]]
@ -820,16 +635,7 @@ version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [ dependencies = [
"windows-targets 0.42.2", "windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
] ]
[[package]] [[package]]
@ -838,28 +644,13 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm 0.42.2", "windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.2", "windows_aarch64_msvc",
"windows_i686_gnu 0.42.2", "windows_i686_gnu",
"windows_i686_msvc 0.42.2", "windows_i686_msvc",
"windows_x86_64_gnu 0.42.2", "windows_x86_64_gnu",
"windows_x86_64_gnullvm 0.42.2", "windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.2", "windows_x86_64_msvc",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
] ]
[[package]] [[package]]
@ -868,93 +659,42 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.2" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.2" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.2" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.2" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.2" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.2" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "ws2_32-sys" name = "ws2_32-sys"
version = "0.2.1" version = "0.2.1"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "rustlings" name = "rustlings"
description = "Small exercises to get you used to reading and writing Rust code!" description = "Small exercises to get you used to reading and writing Rust code!"
version = "5.6.1" version = "5.5.1"
authors = [ authors = [
"Liv <mokou@fastmail.com>", "Liv <mokou@fastmail.com>",
"Carol (Nichols || Goulding) <carol.nichols@gmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>",
@ -9,22 +9,22 @@ authors = [
edition = "2021" edition = "2021"
[dependencies] [dependencies]
indicatif = "0.17.6" argh = "0.1"
indicatif = "0.16"
console = "0.15" console = "0.15"
notify = "4.0" notify = "4.0"
toml = "0.7.6" toml = "0.5"
regex = "1.5" regex = "1.5"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.81" serde_json = "1.0.81"
home = "0.5.3" home = "0.5.3"
glob = "0.3.0" glob = "0.3.0"
clap = { version = "4.4.0", features = ["derive"] }
[[bin]] [[bin]]
name = "rustlings" name = "rustlings"
path = "src/main.rs" path = "src/main.rs"
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.12" assert_cmd = "0.11.0"
predicates = "3.0.3" predicates = "1.0.1"
glob = "0.3.0" glob = "0.3.0"

View File

@ -18,7 +18,7 @@ Alternatively, for a first-time Rust learner, there are several other resources:
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._ _Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
_Note: If you're on Linux, make sure you've installed gcc. Deb: `sudo apt install gcc`. Yum: `sudo yum -y install gcc`._ _Note: If you're on Linux, make sure you've installed gcc. Deb: `sudo apt install gcc`. Yum: `sudo yum -y install gcc`._
You will need to have Rust installed. You can get it by visiting <https://rustup.rs>. This'll also install Cargo, Rust's package/project manager. You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
## MacOS/Linux ## MacOS/Linux
@ -27,7 +27,6 @@ Just run:
```bash ```bash
curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash
``` ```
Or if you want it to be installed to a different path: Or if you want it to be installed to a different path:
```bash ```bash
@ -41,8 +40,8 @@ This will install Rustlings and give you access to the `rustlings` command. Run
Basically: Clone the repository at the latest tag, finally run `nix develop` or `nix-shell`. Basically: Clone the repository at the latest tag, finally run `nix develop` or `nix-shell`.
```bash ```bash
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.6.1) # find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.5.1)
git clone -b 5.6.1 --depth 1 https://github.com/rust-lang/rustlings git clone -b 5.5.1 --depth 1 https://github.com/rust-lang/rustlings
cd rustlings cd rustlings
# if nix version > 2.3 # if nix version > 2.3
nix develop nix develop
@ -79,8 +78,8 @@ If you get a permission denied message, you might have to exclude the directory
Basically: Clone the repository at the latest tag, run `cargo install --path .`. Basically: Clone the repository at the latest tag, run `cargo install --path .`.
```bash ```bash
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.6.1) # find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.5.1)
git clone -b 5.6.1 --depth 1 https://github.com/rust-lang/rustlings git clone -b 5.5.1 --depth 1 https://github.com/rust-lang/rustlings
cd rustlings cd rustlings
cargo install --force --path . cargo install --force --path .
``` ```
@ -173,8 +172,12 @@ Now you should be done!
## Contributing ## Contributing
See [CONTRIBUTING.md](https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md). See [CONTRIBUTING.md](./CONTRIBUTING.md).
Development-focused discussion about Rustlings happens in the [**rustlings** stream](https://rust-lang.zulipchat.com/#narrow/stream/334454-rustlings)
on the [Rust Project Zulip](https://rust-lang.zulipchat.com). Feel free to start a new thread there
if you have ideas or suggestions!
## Contributors ✨ ## Contributors ✨
Thanks goes to the wonderful people listed in [AUTHORS.md](https://github.com/rust-lang/rustlings/blob/main/AUTHORS.md) 🎉 Thanks goes to the wonderful people listed in [AUTHORS.md](./AUTHORS.md) 🎉

View File

@ -1,7 +1,8 @@
// clippy3.rs // clippy3.rs
// //
// Here's a couple more easy Clippy fixes, so you can see its utility. // Here's a couple more easy Clippy fixes, so you can see its utility.
// No hints. //
// Execute `rustlings hint clippy3` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE // I AM NOT DONE

View File

@ -57,7 +57,7 @@ mod tests {
} }
#[test] #[test]
fn mut_box() { fn mult_box() {
let mut num: Box<u32> = Box::new(3); let mut num: Box<u32> = Box::new(3);
num_sq(&mut num); num_sq(&mut num);
assert_eq!(*num, 9); assert_eq!(*num, 9);

View File

@ -127,14 +127,14 @@ mod tests {
#[test] #[test]
fn test_trailing_comma() { fn test_trailing_comma() {
let p: Person = Person::from("Mike,32,"); let p: Person = Person::from("Mike,32,");
assert_eq!(p.name, "Mike"); assert_eq!(p.name, "John");
assert_eq!(p.age, 32); assert_eq!(p.age, 30);
} }
#[test] #[test]
fn test_trailing_comma_and_some_string() { fn test_trailing_comma_and_some_string() {
let p: Person = Person::from("Mike,32,man"); let p: Person = Person::from("Mike,32,man");
assert_eq!(p.name, "Mike"); assert_eq!(p.name, "John");
assert_eq!(p.age, 32); assert_eq!(p.age, 30);
} }
} }

View File

@ -20,7 +20,7 @@ struct State {
color: (u8, u8, u8), color: (u8, u8, u8),
position: Point, position: Point,
quit: bool, quit: bool,
message: String, message: String
} }
impl State { impl State {
@ -32,18 +32,17 @@ impl State {
self.quit = true; self.quit = true;
} }
fn echo(&mut self, s: String) { fn echo(&mut self, s: String) { self.message = s }
self.message = s
}
fn move_position(&mut self, p: Point) { fn move_position(&mut self, p: Point) {
self.position = p; self.position = p;
} }
fn process(&mut self, message: Message) { fn process(&mut self, message: Message) {
// TODO: create a match expression to process the different message variants // TODO: create a match expression to process the different message
// Remember: When passing a tuple as a function argument, you'll need extra parentheses: // variants
// fn function((t, u, p, l, e)) // Remember: When passing a tuple as a function argument, you'll need
// extra parentheses: fn function((t, u, p, l, e))
} }
} }
@ -60,7 +59,7 @@ mod tests {
message: "hello world".to_string(), message: "hello world".to_string(),
}; };
state.process(Message::ChangeColor(255, 0, 255)); state.process(Message::ChangeColor(255, 0, 255));
state.process(Message::Echo(String::from("Hello world!"))); state.process(Message::Echo(String::from("hello world")));
state.process(Message::Move(Point { x: 10, y: 15 })); state.process(Message::Move(Point { x: 10, y: 15 }));
state.process(Message::Quit); state.process(Message::Quit);
@ -68,6 +67,6 @@ mod tests {
assert_eq!(state.position.x, 10); assert_eq!(state.position.x, 10);
assert_eq!(state.position.y, 15); assert_eq!(state.position.y, 15);
assert_eq!(state.quit, true); assert_eq!(state.quit, true);
assert_eq!(state.message, "Hello world!"); assert_eq!(state.message, "hello world");
} }
} }

View File

@ -3,7 +3,7 @@
// This function refuses to generate text to be printed on a nametag if you pass // This function refuses to generate text to be printed on a nametag if you pass
// it an empty string. It'd be nicer if it explained what the problem was, // it an empty string. It'd be nicer if it explained what the problem was,
// instead of just sometimes returning `None`. Thankfully, Rust has a similar // instead of just sometimes returning `None`. Thankfully, Rust has a similar
// construct to `Option` that can be used to express error conditions. Let's use // construct to `Result` that can be used to express error conditions. Let's use
// it! // it!
// //
// Execute `rustlings hint errors1` or use the `hint` watch subcommand for a // Execute `rustlings hint errors1` or use the `hint` watch subcommand for a

View File

@ -9,9 +9,9 @@
// //
// Right now, this function isn't handling the error case at all (and isn't // Right now, this function isn't handling the error case at all (and isn't
// handling the success case properly either). What we want to do is: if we call // handling the success case properly either). What we want to do is: if we call
// the `total_cost` function on a string that is not a number, that function // the `parse` function on a string that is not a number, that function will
// will return a `ParseIntError`, and in that case, we want to immediately // return a `ParseIntError`, and in that case, we want to immediately return
// return that error from our function and not try to multiply and add. // that error from our function and not try to multiply and add.
// //
// There are at least two ways to implement this that are both correct-- but one // There are at least two ways to implement this that are both correct-- but one
// is a lot shorter! // is a lot shorter!

View File

@ -16,7 +16,7 @@ enum CreationError {
impl PositiveNonzeroInteger { impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
// Hmm... Why is this always returning an Ok value? // Hmm...? Why is this only returning an Ok value?
Ok(PositiveNonzeroInteger(value as u64)) Ok(PositiveNonzeroInteger(value as u64))
} }
} }

View File

@ -25,9 +25,4 @@ mod tests {
fn fortytwo_is_bigger_than_thirtytwo() { fn fortytwo_is_bigger_than_thirtytwo() {
assert_eq!(42, bigger(32, 42)); assert_eq!(42, bigger(32, 42));
} }
#[test]
fn equal_numbers() {
assert_eq!(42, bigger(42, 42));
}
} }

View File

@ -1,56 +0,0 @@
// if3.rs
//
// Execute `rustlings hint if3` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
pub fn animal_habitat(animal: &str) -> &'static str {
let identifier = if animal == "crab" {
1
} else if animal == "gopher" {
2.0
} else if animal == "snake" {
3
} else {
"Unknown"
};
// DO NOT CHANGE THIS STATEMENT BELOW
let habitat = if identifier == 1 {
"Beach"
} else if identifier == 2 {
"Burrow"
} else if identifier == 3 {
"Desert"
} else {
"Unknown"
};
habitat
}
// No test changes needed.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gopher_lives_in_burrow() {
assert_eq!(animal_habitat("gopher"), "Burrow")
}
#[test]
fn snake_lives_in_desert() {
assert_eq!(animal_habitat("snake"), "Desert")
}
#[test]
fn crab_lives_on_beach() {
assert_eq!(animal_habitat("crab"), "Beach")
}
#[test]
fn unknown_animal() {
assert_eq!(animal_habitat("dinosaur"), "Unknown")
}
}

View File

@ -11,7 +11,6 @@
// I AM NOT DONE // I AM NOT DONE
#[test]
fn main() { fn main() {
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"]; let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];

View File

@ -5,19 +5,24 @@
// I AM NOT DONE // I AM NOT DONE
#[test]
fn main() { fn main() {
let vec0 = vec![22, 44, 66]; let vec0 = Vec::new();
let vec1 = fill_vec(vec0); let vec1 = fill_vec(vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]); println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
} }
fn fill_vec(vec: Vec<i32>) -> Vec<i32> { fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let vec = vec; let mut vec = vec;
vec.push(88); vec.push(22);
vec.push(44);
vec.push(66);
vec vec
} }

View File

@ -1,26 +1,32 @@
// move_semantics2.rs // move_semantics2.rs
// //
// Make the test pass by finding a way to keep both Vecs separate! // Expected output:
// vec0 has length 3, with contents `[22, 44, 66]`
// vec1 has length 4, with contents `[22, 44, 66, 88]`
// //
// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand // Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand
// for a hint. // for a hint.
// I AM NOT DONE // I AM NOT DONE
#[test]
fn main() { fn main() {
let vec0 = vec![22, 44, 66]; let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0); let mut vec1 = fill_vec(vec0);
assert_eq!(vec0, vec![22, 44, 66]); println!("{} has length {}, with contents: `{:?}`", "vec0", vec0.len(), vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]);
vec1.push(88);
println!("{} has length {}, with contents `{:?}`", "vec1", vec1.len(), vec1);
} }
fn fill_vec(vec: Vec<i32>) -> Vec<i32> { fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec; let mut vec = vec;
vec.push(88); vec.push(22);
vec.push(44);
vec.push(66);
vec vec
} }

View File

@ -1,6 +1,6 @@
// move_semantics3.rs // move_semantics3.rs
// //
// Make me compile without adding new lines -- just changing existing lines! (no // Make me compile without adding new lines-- just changing existing lines! (no
// lines with multiple semicolons necessary!) // lines with multiple semicolons necessary!)
// //
// Execute `rustlings hint move_semantics3` or use the `hint` watch subcommand // Execute `rustlings hint move_semantics3` or use the `hint` watch subcommand
@ -8,17 +8,22 @@
// I AM NOT DONE // I AM NOT DONE
#[test]
fn main() { fn main() {
let vec0 = vec![22, 44, 66]; let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0); let mut vec1 = fill_vec(vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]); println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
} }
fn fill_vec(vec: Vec<i32>) -> Vec<i32> { fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec.push(88); vec.push(22);
vec.push(44);
vec.push(66);
vec vec
} }

View File

@ -9,21 +9,25 @@
// I AM NOT DONE // I AM NOT DONE
#[test]
fn main() { fn main() {
let vec0 = vec![22, 44, 66]; let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0); let mut vec1 = fill_vec(vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]); println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
} }
// `fill_vec()` no longer takes `vec: Vec<i32>` as argument - don't change this! // `fill_vec()` no longer takes `vec: Vec<i32>` as argument
fn fill_vec() -> Vec<i32> { fn fill_vec() -> Vec<i32> {
// Instead, let's create and fill the Vec in here - how do you do that?
let mut vec = vec; let mut vec = vec;
vec.push(88); vec.push(22);
vec.push(44);
vec.push(66);
vec vec
} }

View File

@ -8,7 +8,6 @@
// I AM NOT DONE // I AM NOT DONE
#[test]
fn main() { fn main() {
let mut x = 100; let mut x = 100;
let y = &mut x; let y = &mut x;

View File

@ -2,6 +2,9 @@
// //
// Fill in the rest of the line that has code missing! No hints, there's no // Fill in the rest of the line that has code missing! No hints, there's no
// tricks, just get used to typing these :) // tricks, just get used to typing these :)
//
// Execute `rustlings hint primitive_types1` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE // I AM NOT DONE

View File

@ -2,6 +2,9 @@
// //
// Fill in the rest of the line that has code missing! No hints, there's no // Fill in the rest of the line that has code missing! No hints, there's no
// tricks, just get used to typing these :) // tricks, just get used to typing these :)
//
// Execute `rustlings hint primitive_types2` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE // I AM NOT DONE

View File

@ -14,6 +14,5 @@ fn main() {
println!("Wow, that's a big array!"); println!("Wow, that's a big array!");
} else { } else {
println!("Meh, I eat arrays like that for breakfast."); println!("Meh, I eat arrays like that for breakfast.");
panic!("Array not big enough, more elements needed")
} }
} }

View File

@ -9,7 +9,7 @@
// - An apple costs 2 rustbucks. // - An apple costs 2 rustbucks.
// - If Mary buys more than 40 apples, each apple only costs 1 rustbuck! // - If Mary buys more than 40 apples, each apple only costs 1 rustbuck!
// Write a function that calculates the price of an order of apples given the // Write a function that calculates the price of an order of apples given the
// quantity bought. // quantity bought. No hints this time!
// //
// No hints this time ;) // No hints this time ;)

View File

@ -67,8 +67,8 @@ mod tests {
#[test] #[test]
fn owned_mutation() -> Result<(), &'static str> { fn owned_mutation() -> Result<(), &'static str> {
// Of course this is also the case if a mutation does occur. In this // Of course this is also the case if a mutation does occur. In this
// case the call to `to_mut()` in the abs_all() function returns a // case the call to `to_mut()` returns a reference to the same data as
// reference to the same data as before. // before.
let slice = vec![-1, 0, 1]; let slice = vec![-1, 0, 1];
let mut input = Cow::from(slice); let mut input = Cow::from(slice);
match abs_all(&mut input) { match abs_all(&mut input) {

View File

@ -35,7 +35,6 @@ impl Planet {
} }
} }
#[test]
fn main() { fn main() {
let sun = Rc::new(Sun {}); let sun = Rc::new(Sun {});
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference

View File

@ -13,15 +13,13 @@
struct Package { struct Package {
sender_country: String, sender_country: String,
recipient_country: String, recipient_country: String,
weight_in_grams: u32, weight_in_grams: i32,
} }
impl Package { impl Package {
fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Package { fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
if weight_in_grams < 10 { if weight_in_grams <= 0 {
// This is not how you should handle errors in Rust, panic!("Can not ship a weightless package.")
// but we will learn about error handling later.
panic!("Can not ship a package with weight below 10 grams.")
} else { } else {
Package { Package {
sender_country, sender_country,
@ -35,7 +33,7 @@ impl Package {
// Something goes here... // Something goes here...
} }
fn get_fees(&self, cents_per_gram: u32) -> ??? { fn get_fees(&self, cents_per_gram: i32) -> ??? {
// Something goes here... // Something goes here...
} }
} }
@ -50,7 +48,7 @@ mod tests {
let sender_country = String::from("Spain"); let sender_country = String::from("Spain");
let recipient_country = String::from("Austria"); let recipient_country = String::from("Austria");
Package::new(sender_country, recipient_country, 5); Package::new(sender_country, recipient_country, -2210);
} }
#[test] #[test]

View File

@ -1,6 +1,6 @@
# Threads # Threads
In most current operating systems, an executed program's code is run in a process, and the operating system manages multiple processes at once. In most current operating systems, an executed programs code is run in a process, and the operating system manages multiple processes at once.
Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads. Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads.
## Further information ## Further information

View File

@ -48,7 +48,6 @@ fn send_tx(q: Queue, tx: mpsc::Sender<u32>) -> () {
}); });
} }
#[test]
fn main() { fn main() {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let queue = Queue::new(); let queue = Queue::new();

View File

@ -3,11 +3,11 @@
"flake-compat": { "flake-compat": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1673956053, "lastModified": 1650374568,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "rev": "b4a34015c698c7793d592d66adbab377907a2be8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -17,15 +17,12 @@
} }
}, },
"flake-utils": { "flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": { "locked": {
"lastModified": 1692799911, "lastModified": 1659877975,
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -36,11 +33,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1694183432, "lastModified": 1666629043,
"narHash": "sha256-YyPGNapgZNNj51ylQMw9lAgvxtM2ai1HZVUu3GS8Fng=", "narHash": "sha256-Yoq6Ut2F3Ol73yO9hG93x6ts5c4F5BhKTbcF3DtBEAw=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "db9208ab987cdeeedf78ad9b4cf3c55f5ebd269b", "rev": "b39fd6e4edef83cb4a135ebef98751ce23becc33",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -56,21 +53,6 @@
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View File

@ -22,10 +22,9 @@
rustlings = rustlings =
pkgs.rustPlatform.buildRustPackage { pkgs.rustPlatform.buildRustPackage {
name = "rustlings"; name = "rustlings";
version = "5.6.1"; version = "5.5.1";
buildInputs = cargoBuildInputs; buildInputs = cargoBuildInputs;
nativeBuildInputs = [pkgs.git];
src = with pkgs.lib; cleanSourceWith { src = with pkgs.lib; cleanSourceWith {
src = self; src = self;
@ -61,18 +60,5 @@
clippy clippy
] ++ cargoBuildInputs; ] ++ cargoBuildInputs;
}; };
apps = let
rustlings-app = {
type = "app";
program = "${rustlings}/bin/rustlings";
};
in {
default = rustlings-app;
rustlings = rustlings-app;
};
packages = {
inherit rustlings;
default = rustlings;
};
}); });
} }

View File

@ -22,8 +22,8 @@ name = "variables1"
path = "exercises/variables/variables1.rs" path = "exercises/variables/variables1.rs"
mode = "compile" mode = "compile"
hint = """ hint = """
The declaration in the first line in the main function is missing a keyword The declaration on line 8 is missing a keyword that is needed in Rust
that is needed in Rust to create a new variable binding.""" to create a new variable binding."""
[[exercises]] [[exercises]]
name = "variables2" name = "variables2"
@ -32,7 +32,7 @@ mode = "compile"
hint = """ hint = """
The compiler message is saying that Rust cannot infer the type that the The compiler message is saying that Rust cannot infer the type that the
variable binding `x` has with what is given here. variable binding `x` has with what is given here.
What happens if you annotate the first line in the main function with a type annotation? What happens if you annotate line 7 with a type annotation?
What if you give x a value? What if you give x a value?
What if you do both? What if you do both?
What type should x be, anyway? What type should x be, anyway?
@ -44,9 +44,8 @@ path = "exercises/variables/variables3.rs"
mode = "compile" mode = "compile"
hint = """ hint = """
Oops! In this exercise, we have a variable binding that we've created on Oops! In this exercise, we have a variable binding that we've created on
in the first line in the main function, and we're trying to use it in the next line, line 7, and we're trying to use it on line 8, but we haven't given it a
but we haven't given it a value. value. We can't print out something that isn't there; try giving x 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 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!""" programming language -- thankfully the Rust compiler has caught this for us!"""
@ -124,8 +123,8 @@ name = "functions4"
path = "exercises/functions/functions4.rs" path = "exercises/functions/functions4.rs"
mode = "compile" mode = "compile"
hint = """ hint = """
The error message points to the function `sale_price` and says it expects a type The error message points to line 17 and says it expects a type after the
after the `->`. This is where the function's return type should be -- take a look at `->`. This is where the function's return type should be -- take a look at
the `is_even` function for an example! the `is_even` function for an example!
Also: Did you figure out that, technically, u32 would be the more fitting type Also: Did you figure out that, technically, u32 would be the more fitting type
@ -168,13 +167,6 @@ For that first compiler error, it's important in Rust that each conditional
block returns the same type! To get the tests passing, you will need a couple block returns the same type! To get the tests passing, you will need a couple
conditions checking different input values.""" conditions checking different input values."""
[[exercises]]
name = "if3"
path = "exercises/if/if3.rs"
mode = "test"
hint = """
In Rust, every arm of an `if` expression has to return the same type of value. Make sure the type is consistent across all arms."""
# QUIZ 1 # QUIZ 1
[[exercises]] [[exercises]]
@ -217,7 +209,7 @@ mode = "test"
hint = """ hint = """
Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book: Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book:
https://doc.rust-lang.org/book/ch04-03-slices.html https://doc.rust-lang.org/book/ch04-03-slices.html
and use the starting and ending (plus one) indices of the items in the Array and use the starting and ending indices of the items in the Array
that you want to end up in the slice. that you want to end up in the slice.
If you're curious why the first argument of `assert_eq!` does not If you're curious why the first argument of `assert_eq!` does not
@ -268,14 +260,15 @@ name = "vecs2"
path = "exercises/vecs/vecs2.rs" path = "exercises/vecs/vecs2.rs"
mode = "test" mode = "test"
hint = """ hint = """
In the first function we are looping over the Vector and getting a reference to one `element` at a time. Hint 1: In the code, the variable `element` represents an item from the Vec as it is being iterated.
To modify the value of that `element` we need to use the * dereference operator. You can learn more in this chapter of the Rust book: Can you try multiplying this?
https://doc.rust-lang.org/stable/book/ch08-01-vectors.html#iterating-over-the-values-in-a-vector
In the second function this dereferencing is not necessary, because the map function expects the new value to be returned. Hint 2: For the first function, there's a way to directly access the numbers stored
in the Vec, using the * dereference operator. You can both access and write to the
number that way.
After you've completed both functions, decide for yourself which approach you like better. After you've completed both functions, decide for yourself which approach you like
What do you think is the more commonly used pattern under Rust developers? better. What do you think is the more commonly used pattern under Rust developers?
""" """
# MOVE SEMANTICS # MOVE SEMANTICS
@ -283,19 +276,18 @@ What do you think is the more commonly used pattern under Rust developers?
[[exercises]] [[exercises]]
name = "move_semantics1" name = "move_semantics1"
path = "exercises/move_semantics/move_semantics1.rs" path = "exercises/move_semantics/move_semantics1.rs"
mode = "test" mode = "compile"
hint = """ hint = """
So you've got the "cannot borrow immutable local variable `vec` as mutable" error on the line So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 13,
where we push an element to the vector, right? right? The fix for this is going to be adding one keyword, and the addition is NOT on line 13
The fix for this is going to be adding one keyword, and the addition is NOT on the line where where the error is.
we push to the vector (where the error is).
Also: Try accessing `vec0` after having called `fill_vec()`. See what happens!""" Also: Try accessing `vec0` after having called `fill_vec()`. See what happens!"""
[[exercises]] [[exercises]]
name = "move_semantics2" name = "move_semantics2"
path = "exercises/move_semantics/move_semantics2.rs" path = "exercises/move_semantics/move_semantics2.rs"
mode = "test" mode = "compile"
hint = """ hint = """
When running this exercise for the first time, you'll notice an error about When running this exercise for the first time, you'll notice an error about
"borrow of moved value". In Rust, when an argument is passed to a function and "borrow of moved value". In Rust, when an argument is passed to a function and
@ -308,12 +300,16 @@ Rust provides a couple of different ways to mitigate this issue, feel free to tr
2. Make `fill_vec` borrow its argument instead of taking ownership of it, 2. Make `fill_vec` borrow its argument instead of taking ownership of it,
and then copy the data within the function (`vec.clone()`) in order to return an owned and then copy the data within the function (`vec.clone()`) in order to return an owned
`Vec<i32>`. `Vec<i32>`.
3. Or, you could make `fill_vec` *mutably* borrow a reference to its argument (which will need to be
mutable), modify it directly, then not return anything. This means that `vec0` will change over the
course of the function, and makes `vec1` redundant (make sure to change the parameters of the `println!`
statements if you go this route)
""" """
[[exercises]] [[exercises]]
name = "move_semantics3" name = "move_semantics3"
path = "exercises/move_semantics/move_semantics3.rs" path = "exercises/move_semantics/move_semantics3.rs"
mode = "test" mode = "compile"
hint = """ hint = """
The difference between this one and the previous ones is that the first line 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, of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can,
@ -323,7 +319,7 @@ an existing binding to be a mutable binding instead of an immutable one :)"""
[[exercises]] [[exercises]]
name = "move_semantics4" name = "move_semantics4"
path = "exercises/move_semantics/move_semantics4.rs" path = "exercises/move_semantics/move_semantics4.rs"
mode = "test" mode = "compile"
hint = """ hint = """
Stop reading whenever you feel like you have enough direction :) Or try Stop reading whenever you feel like you have enough direction :) Or try
doing one step and then fixing the compiler errors that result! doing one step and then fixing the compiler errors that result!
@ -332,12 +328,12 @@ So the end goal is to:
- so then `vec0` doesn't exist, so we can't pass it to `fill_vec` - so then `vec0` doesn't exist, so we can't pass it to `fill_vec`
- `fill_vec` has had its signature changed, which our call should reflect - `fill_vec` has had its signature changed, which our call should reflect
- since we're not creating a new vec in `main` anymore, we need to create - since we're not creating a new vec in `main` anymore, we need to create
a new vec in `fill_vec`, and fill it with the expected values""" a new vec in `fill_vec`, similarly to the way we did in `main`"""
[[exercises]] [[exercises]]
name = "move_semantics5" name = "move_semantics5"
path = "exercises/move_semantics/move_semantics5.rs" path = "exercises/move_semantics/move_semantics5.rs"
mode = "test" mode = "compile"
hint = """ hint = """
Carefully reason about the range in which each mutable reference is in Carefully reason about the range in which each mutable reference is in
scope. Does it help to update the value of referent (x) immediately after scope. Does it help to update the value of referent (x) immediately after
@ -442,8 +438,8 @@ path = "exercises/strings/strings2.rs"
mode = "compile" mode = "compile"
hint = """ hint = """
Yes, it would be really easy to fix this by just changing the value bound to `word` to be a 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 the string slice instead of a `String`, wouldn't it?? There is a way to add one character to line
if statement, though, that will coerce the `String` into a string slice. 9, though, that will coerce the `String` into a string slice.
Side note: If you're interested in learning about how this kind of reference conversion works, you can jump ahead in the book and read this part in the smart pointers chapter: https://doc.rust-lang.org/stable/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods""" Side note: If you're interested in learning about how this kind of reference conversion works, you can jump ahead in the book and read this part in the smart pointers chapter: https://doc.rust-lang.org/stable/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods"""
@ -822,12 +818,13 @@ To handle that you need to add a special attribute to the test function.
You can refer to the docs: You can refer to the docs:
https://doc.rust-lang.org/stable/book/ch11-01-writing-tests.html#checking-for-panics-with-should_panic""" https://doc.rust-lang.org/stable/book/ch11-01-writing-tests.html#checking-for-panics-with-should_panic"""
# STANDARD LIBRARY TYPES # STANDARD LIBRARY TYPES
[[exercises]] [[exercises]]
name = "iterators1" name = "iterators1"
path = "exercises/iterators/iterators1.rs" path = "exercises/iterators/iterators1.rs"
mode = "test" mode = "compile"
hint = """ hint = """
Step 1: Step 1:
We need to apply something to the collection `my_fav_fruits` before we start to go through We need to apply something to the collection `my_fav_fruits` before we start to go through
@ -932,7 +929,7 @@ and try other types!
[[exercises]] [[exercises]]
name = "rc1" name = "rc1"
path = "exercises/smart_pointers/rc1.rs" path = "exercises/smart_pointers/rc1.rs"
mode = "test" mode = "compile"
hint = """ hint = """
This is a straightforward exercise to use the Rc<T> type. Each Planet has This is a straightforward exercise to use the Rc<T> type. Each Planet has
ownership of the Sun, and uses Rc::clone() to increment the reference count of the Sun. ownership of the Sun, and uses Rc::clone() to increment the reference count of the Sun.
@ -1005,7 +1002,7 @@ and keep reading if you'd like more hints :)
Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like: Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like:
`let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));` `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 Similar to the code in the example in the book that happens after the text
that says "Sharing a Mutex<T> Between Multiple Threads". If not, give that a try! If you 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!! do and would like more hints, keep reading!!
@ -1021,7 +1018,7 @@ what you've learned :)"""
[[exercises]] [[exercises]]
name = "threads3" name = "threads3"
path = "exercises/threads/threads3.rs" path = "exercises/threads/threads3.rs"
mode = "test" mode = "compile"
hint = """ hint = """
An alternate way to handle concurrency between threads is to use An alternate way to handle concurrency between threads is to use
a mpsc (multiple producer, single consumer) channel to communicate. a mpsc (multiple producer, single consumer) channel to communicate.

View File

@ -1,24 +1,10 @@
{ {
"project": { "homepage": "https://rustlings.cool",
"homepage": "https://rustlings.cool", "repository": "https://github.com/rust-lang/rustlings",
"repository": "https://github.com/rust-lang/rustlings" "analytics": {
}, "plausible": {
"marketing": { "domain": "rustlings.cool"
"analytics": {
"plausible": {
"domain": "rustlings.cool"
}
} }
}, },
"components": { "changelog": false
"artifacts": {
"auto": true,
"package_managers": {
"preferred": {
"macos/linux/unix": "curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash",
"windows": "Start-BitsTransfer -Source https://raw.githubusercontent.com/rust-lang/rustlings/main/install.ps1 -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1"
}
}
}
}
} }

View File

@ -110,12 +110,12 @@ impl Exercise {
pub fn compile(&self) -> Result<CompiledExercise, ExerciseOutput> { pub fn compile(&self) -> Result<CompiledExercise, ExerciseOutput> {
let cmd = match self.mode { let cmd = match self.mode {
Mode::Compile => Command::new("rustc") Mode::Compile => Command::new("rustc")
.args([self.path.to_str().unwrap(), "-o", &temp_file()]) .args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS) .args(RUSTC_COLOR_ARGS)
.args(RUSTC_EDITION_ARGS) .args(RUSTC_EDITION_ARGS)
.output(), .output(),
Mode::Test => Command::new("rustc") Mode::Test => Command::new("rustc")
.args(["--test", self.path.to_str().unwrap(), "-o", &temp_file()]) .args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS) .args(RUSTC_COLOR_ARGS)
.args(RUSTC_EDITION_ARGS) .args(RUSTC_EDITION_ARGS)
.output(), .output(),
@ -141,7 +141,7 @@ path = "{}.rs""#,
// compilation failure, this would silently fail. But we expect // compilation failure, this would silently fail. But we expect
// clippy to reflect the same failure while compiling later. // clippy to reflect the same failure while compiling later.
Command::new("rustc") Command::new("rustc")
.args([self.path.to_str().unwrap(), "-o", &temp_file()]) .args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS) .args(RUSTC_COLOR_ARGS)
.args(RUSTC_EDITION_ARGS) .args(RUSTC_EDITION_ARGS)
.output() .output()
@ -151,14 +151,14 @@ path = "{}.rs""#,
// This is already fixed on Clippy's master branch. See this issue to track merging into Cargo: // This is already fixed on Clippy's master branch. See this issue to track merging into Cargo:
// https://github.com/rust-lang/rust-clippy/issues/3837 // https://github.com/rust-lang/rust-clippy/issues/3837
Command::new("cargo") Command::new("cargo")
.args(["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH]) .args(&["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS) .args(RUSTC_COLOR_ARGS)
.output() .output()
.expect("Failed to run 'cargo clean'"); .expect("Failed to run 'cargo clean'");
Command::new("cargo") Command::new("cargo")
.args(["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH]) .args(&["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS) .args(RUSTC_COLOR_ARGS)
.args(["--", "-D", "warnings", "-D", "clippy::float_cmp"]) .args(&["--", "-D", "warnings", "-D", "clippy::float_cmp"])
.output() .output()
} }
} }
@ -183,7 +183,7 @@ path = "{}.rs""#,
Mode::Test => "--show-output", Mode::Test => "--show-output",
_ => "", _ => "",
}; };
let cmd = Command::new(temp_file()) let cmd = Command::new(&temp_file())
.arg(arg) .arg(arg)
.output() .output()
.expect("Failed to run 'run' command"); .expect("Failed to run 'run' command");
@ -260,7 +260,7 @@ impl Display for Exercise {
#[inline] #[inline]
fn clean() { fn clean() {
let _ignored = remove_file(temp_file()); let _ignored = remove_file(&temp_file());
} }
#[cfg(test)] #[cfg(test)]
@ -270,7 +270,7 @@ mod test {
#[test] #[test]
fn test_clean() { fn test_clean() {
File::create(temp_file()).unwrap(); File::create(&temp_file()).unwrap();
let exercise = Exercise { let exercise = Exercise {
name: String::from("example"), name: String::from("example"),
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"), path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),

View File

@ -2,7 +2,7 @@ use crate::exercise::{Exercise, ExerciseList};
use crate::project::RustAnalyzerProject; use crate::project::RustAnalyzerProject;
use crate::run::{reset, run}; use crate::run::{reset, run};
use crate::verify::verify; use crate::verify::verify;
use clap::{Parser, Subcommand}; use argh::FromArgs;
use console::Emoji; use console::Emoji;
use notify::DebouncedEvent; use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use notify::{RecommendedWatcher, RecursiveMode, Watcher};
@ -25,69 +25,111 @@ mod project;
mod run; mod run;
mod verify; mod verify;
// In sync with crate version
const VERSION: &str = "5.5.1";
#[derive(FromArgs, PartialEq, Debug)]
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
#[derive(Parser)]
#[command(version)]
struct Args { struct Args {
/// Show outputs from the test exercises /// show outputs from the test exercises
#[arg(long)] #[argh(switch)]
nocapture: bool, nocapture: bool,
#[command(subcommand)] /// show the executable version
command: Option<Subcommands>, #[argh(switch, short = 'v')]
version: bool,
#[argh(subcommand)]
nested: Option<Subcommands>,
} }
#[derive(Subcommand)] #[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum Subcommands { enum Subcommands {
/// Verify all exercises according to the recommended order Verify(VerifyArgs),
Verify, Watch(WatchArgs),
/// Rerun `verify` when files were edited Run(RunArgs),
Watch { Reset(ResetArgs),
/// Show hints on success Hint(HintArgs),
#[arg(long)] List(ListArgs),
success_hints: bool, Lsp(LspArgs),
}, }
/// Run/Test a single exercise
Run { #[derive(FromArgs, PartialEq, Debug)]
/// The name of the exercise #[argh(subcommand, name = "verify")]
name: String, /// Verifies all exercises according to the recommended order
}, struct VerifyArgs {}
/// Reset a single exercise using "git stash -- <filename>"
Reset { #[derive(FromArgs, PartialEq, Debug)]
/// The name of the exercise #[argh(subcommand, name = "watch")]
name: String, /// Reruns `verify` when files were edited
}, struct WatchArgs {
/// Return a hint for the given exercise /// show hints on success
Hint { #[argh(switch)]
/// The name of the exercise success_hints: bool,
name: String, }
},
/// List the exercises available in Rustlings #[derive(FromArgs, PartialEq, Debug)]
List { #[argh(subcommand, name = "run")]
/// Show only the paths of the exercises /// Runs/Tests a single exercise
#[arg(short, long)] struct RunArgs {
paths: bool, #[argh(positional)]
/// Show only the names of the exercises /// the name of the exercise
#[arg(short, long)] name: String,
names: bool, }
/// Provide a string to match exercise names.
/// Comma separated patterns are accepted #[derive(FromArgs, PartialEq, Debug)]
#[arg(short, long)] #[argh(subcommand, name = "reset")]
filter: Option<String>, /// Resets a single exercise using "git stash -- <filename>"
/// Display only exercises not yet solved struct ResetArgs {
#[arg(short, long)] #[argh(positional)]
unsolved: bool, /// the name of the exercise
/// Display only exercises that have been solved name: String,
#[arg(short, long)] }
solved: bool,
}, #[derive(FromArgs, PartialEq, Debug)]
/// Enable rust-analyzer for exercises #[argh(subcommand, name = "hint")]
Lsp, /// Returns a hint for the given exercise
struct HintArgs {
#[argh(positional)]
/// the name of the exercise
name: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "lsp")]
/// Enable rust-analyzer for exercises
struct LspArgs {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "list")]
/// Lists the exercises available in Rustlings
struct ListArgs {
#[argh(switch, short = 'p')]
/// show only the paths of the exercises
paths: bool,
#[argh(switch, short = 'n')]
/// show only the names of the exercises
names: bool,
#[argh(option, short = 'f')]
/// provide a string to match exercise names
/// comma separated patterns are acceptable
filter: Option<String>,
#[argh(switch, short = 'u')]
/// display only exercises not yet solved
unsolved: bool,
#[argh(switch, short = 's')]
/// display only exercises that have been solved
solved: bool,
} }
fn main() { fn main() {
let args = Args::parse(); let args: Args = argh::from_env();
if args.command.is_none() { if args.version {
println!("v{VERSION}");
std::process::exit(0);
}
if args.nested.is_none() {
println!("\n{WELCOME}\n"); println!("\n{WELCOME}\n");
} }
@ -111,30 +153,23 @@ fn main() {
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises; let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
let verbose = args.nocapture; let verbose = args.nocapture;
let command = args.command.unwrap_or_else(|| { let command = args.nested.unwrap_or_else(|| {
println!("{DEFAULT_OUT}\n"); println!("{DEFAULT_OUT}\n");
std::process::exit(0); std::process::exit(0);
}); });
match command { match command {
Subcommands::List { Subcommands::List(subargs) => {
paths, if !subargs.paths && !subargs.names {
names,
filter,
unsolved,
solved,
} => {
if !paths && !names {
println!("{:<17}\t{:<46}\t{:<7}", "Name", "Path", "Status"); println!("{:<17}\t{:<46}\t{:<7}", "Name", "Path", "Status");
} }
let mut exercises_done: u16 = 0; let mut exercises_done: u16 = 0;
let filters = filter.clone().unwrap_or_default().to_lowercase(); let filters = subargs.filter.clone().unwrap_or_default().to_lowercase();
exercises.iter().for_each(|e| { exercises.iter().for_each(|e| {
let fname = format!("{}", e.path.display()); let fname = format!("{}", e.path.display());
let filter_cond = filters let filter_cond = filters
.split(',') .split(',')
.filter(|f| !f.trim().is_empty()) .filter(|f| !f.trim().is_empty())
.any(|f| e.name.contains(f) || fname.contains(f)); .any(|f| e.name.contains(&f) || fname.contains(&f));
let status = if e.looks_done() { let status = if e.looks_done() {
exercises_done += 1; exercises_done += 1;
"Done" "Done"
@ -142,14 +177,14 @@ fn main() {
"Pending" "Pending"
}; };
let solve_cond = { let solve_cond = {
(e.looks_done() && solved) (e.looks_done() && subargs.solved)
|| (!e.looks_done() && unsolved) || (!e.looks_done() && subargs.unsolved)
|| (!solved && !unsolved) || (!subargs.solved && !subargs.unsolved)
}; };
if solve_cond && (filter_cond || filter.is_none()) { if solve_cond && (filter_cond || subargs.filter.is_none()) {
let line = if paths { let line = if subargs.paths {
format!("{fname}\n") format!("{fname}\n")
} else if names { } else if subargs.names {
format!("{}\n", e.name) format!("{}\n", e.name)
} else { } else {
format!("{:<17}\t{fname:<46}\t{status:<7}\n", e.name) format!("{:<17}\t{fname:<46}\t{status:<7}\n", e.name)
@ -179,30 +214,30 @@ fn main() {
std::process::exit(0); std::process::exit(0);
} }
Subcommands::Run { name } => { Subcommands::Run(subargs) => {
let exercise = find_exercise(&name, &exercises); let exercise = find_exercise(&subargs.name, &exercises);
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1)); run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
} }
Subcommands::Reset { name } => { Subcommands::Reset(subargs) => {
let exercise = find_exercise(&name, &exercises); let exercise = find_exercise(&subargs.name, &exercises);
reset(exercise).unwrap_or_else(|_| std::process::exit(1)); reset(exercise).unwrap_or_else(|_| std::process::exit(1));
} }
Subcommands::Hint { name } => { Subcommands::Hint(subargs) => {
let exercise = find_exercise(&name, &exercises); let exercise = find_exercise(&subargs.name, &exercises);
println!("{}", exercise.hint); println!("{}", exercise.hint);
} }
Subcommands::Verify => { Subcommands::Verify(_subargs) => {
verify(&exercises, (0, exercises.len()), verbose, false) verify(&exercises, (0, exercises.len()), verbose, false)
.unwrap_or_else(|_| std::process::exit(1)); .unwrap_or_else(|_| std::process::exit(1));
} }
Subcommands::Lsp => { Subcommands::Lsp(_subargs) => {
let mut project = RustAnalyzerProject::new(); let mut project = RustAnalyzerProject::new();
project project
.get_sysroot_src() .get_sysroot_src()
@ -221,7 +256,7 @@ fn main() {
} }
} }
Subcommands::Watch { success_hints } => match watch(&exercises, verbose, success_hints) { Subcommands::Watch(_subargs) => match watch(&exercises, verbose, _subargs.success_hints) {
Err(e) => { Err(e) => {
println!( println!(
"Error: Could not watch your progress. Error message was {:?}.", "Error: Could not watch your progress. Error message was {:?}.",
@ -394,7 +429,7 @@ fn watch(
fn rustc_exists() -> bool { fn rustc_exists() -> bool {
Command::new("rustc") Command::new("rustc")
.args(["--version"]) .args(&["--version"])
.stdout(Stdio::null()) .stdout(Stdio::null())
.spawn() .spawn()
.and_then(|mut child| child.wait()) .and_then(|mut child| child.wait())
@ -430,7 +465,7 @@ started, here's a couple of notes about how Rustlings operates:
Got all that? Great! To get started, run `rustlings watch` in order to get the first Got all that? Great! To get started, run `rustlings watch` in order to get the first
exercise. Make sure to have your editor open!"#; exercise. Make sure to have your editor open!"#;
const FENISH_LINE: &str = r"+----------------------------------------------------+ const FENISH_LINE: &str = r#"+----------------------------------------------------+
| You made it to the Fe-nish line! | | You made it to the Fe-nish line! |
+-------------------------- ------------------------+ +-------------------------- ------------------------+
\\/ \\/
@ -455,12 +490,12 @@ If you noticed any issues, please don't hesitate to report them to our repo.
You can also contribute your own exercises to help the greater community! You can also contribute your own exercises to help the greater community!
Before reporting an issue or contributing, please read our guidelines: Before reporting an issue or contributing, please read our guidelines:
https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"; https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"#;
const WELCOME: &str = r" welcome to... const WELCOME: &str = r#" welcome to...
_ _ _ _ _ _
_ __ _ _ ___| |_| (_)_ __ __ _ ___ _ __ _ _ ___| |_| (_)_ __ __ _ ___
| '__| | | / __| __| | | '_ \ / _` / __| | '__| | | / __| __| | | '_ \ / _` / __|
| | | |_| \__ \ |_| | | | | | (_| \__ \ | | | |_| \__ \ |_| | | | | | (_| \__ \
|_| \__,_|___/\__|_|_|_| |_|\__, |___/ |_| \__,_|___/\__|_|_|_| |_|\__, |___/
|___/"; |___/"#;

View File

@ -86,7 +86,7 @@ impl RustAnalyzerProject {
println!("Determined toolchain: {}\n", &toolchain); println!("Determined toolchain: {}\n", &toolchain);
self.sysroot_src = (std::path::Path::new(toolchain) self.sysroot_src = (std::path::Path::new(&*toolchain)
.join("lib") .join("lib")
.join("rustlib") .join("rustlib")
.join("src") .join("src")

View File

@ -1,5 +1,4 @@
use std::process::Command; use std::process::Command;
use std::time::Duration;
use crate::exercise::{Exercise, Mode}; use crate::exercise::{Exercise, Mode};
use crate::verify::test; use crate::verify::test;
@ -37,7 +36,7 @@ pub fn reset(exercise: &Exercise) -> Result<(), ()> {
fn compile_and_run(exercise: &Exercise) -> Result<(), ()> { fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
let progress_bar = ProgressBar::new_spinner(); let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {exercise}...")); progress_bar.set_message(format!("Compiling {exercise}..."));
progress_bar.enable_steady_tick(Duration::from_millis(100)); progress_bar.enable_steady_tick(100);
let compilation_result = exercise.compile(); let compilation_result = exercise.compile();
let compilation = match compilation_result { let compilation = match compilation_result {

View File

@ -1,7 +1,7 @@
use crate::exercise::{CompiledExercise, Exercise, Mode, State}; use crate::exercise::{CompiledExercise, Exercise, Mode, State};
use console::style; use console::style;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use std::{env, time::Duration}; use std::env;
// Verify that the provided container of Exercise objects // Verify that the provided container of Exercise objects
// can be compiled and run without any failures. // can be compiled and run without any failures.
@ -17,11 +17,9 @@ pub fn verify<'a>(
let (num_done, total) = progress; let (num_done, total) = progress;
let bar = ProgressBar::new(total as u64); let bar = ProgressBar::new(total as u64);
let mut percentage = num_done as f32 / total as f32 * 100.0; let mut percentage = num_done as f32 / total as f32 * 100.0;
bar.set_style( bar.set_style(ProgressStyle::default_bar()
ProgressStyle::default_bar() .template("Progress: [{bar:60.green/red}] {pos}/{len} {msg}")
.template("Progress: [{bar:60.green/red}] {pos}/{len} {msg}") .progress_chars("#>-")
.expect("Progressbar template should be valid!")
.progress_chars("#>-"),
); );
bar.set_position(num_done as u64); bar.set_position(num_done as u64);
bar.set_message(format!("({:.1} %)", percentage)); bar.set_message(format!("({:.1} %)", percentage));
@ -57,7 +55,7 @@ pub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
fn compile_only(exercise: &Exercise, success_hints: bool) -> Result<bool, ()> { fn compile_only(exercise: &Exercise, success_hints: bool) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner(); let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {exercise}...")); progress_bar.set_message(format!("Compiling {exercise}..."));
progress_bar.enable_steady_tick(Duration::from_millis(100)); progress_bar.enable_steady_tick(100);
let _ = compile(exercise, &progress_bar)?; let _ = compile(exercise, &progress_bar)?;
progress_bar.finish_and_clear(); progress_bar.finish_and_clear();
@ -69,7 +67,7 @@ fn compile_only(exercise: &Exercise, success_hints: bool) -> Result<bool, ()> {
fn compile_and_run_interactively(exercise: &Exercise, success_hints: bool) -> Result<bool, ()> { fn compile_and_run_interactively(exercise: &Exercise, success_hints: bool) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner(); let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {exercise}...")); progress_bar.set_message(format!("Compiling {exercise}..."));
progress_bar.enable_steady_tick(Duration::from_millis(100)); progress_bar.enable_steady_tick(100);
let compilation = compile(exercise, &progress_bar)?; let compilation = compile(exercise, &progress_bar)?;
@ -87,24 +85,15 @@ fn compile_and_run_interactively(exercise: &Exercise, success_hints: bool) -> Re
} }
}; };
Ok(prompt_for_completion( Ok(prompt_for_completion(exercise, Some(output.stdout), success_hints))
exercise,
Some(output.stdout),
success_hints,
))
} }
// Compile the given Exercise as a test harness and display // Compile the given Exercise as a test harness and display
// the output if verbose is set to true // the output if verbose is set to true
fn compile_and_test( fn compile_and_test(exercise: &Exercise, run_mode: RunMode, verbose: bool, success_hints: bool) -> Result<bool, ()> {
exercise: &Exercise,
run_mode: RunMode,
verbose: bool,
success_hints: bool,
) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner(); let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Testing {exercise}...")); progress_bar.set_message(format!("Testing {exercise}..."));
progress_bar.enable_steady_tick(Duration::from_millis(100)); progress_bar.enable_steady_tick(100);
let compilation = compile(exercise, &progress_bar)?; let compilation = compile(exercise, &progress_bar)?;
let result = compilation.run(); let result = compilation.run();
@ -134,9 +123,9 @@ fn compile_and_test(
// Compile the given Exercise and return an object with information // Compile the given Exercise and return an object with information
// about the state of the compilation // about the state of the compilation
fn compile<'a>( fn compile<'a, 'b>(
exercise: &'a Exercise, exercise: &'a Exercise,
progress_bar: &ProgressBar, progress_bar: &'b ProgressBar,
) -> Result<CompiledExercise<'a>, ()> { ) -> Result<CompiledExercise<'a>, ()> {
let compilation_result = exercise.compile(); let compilation_result = exercise.compile();
@ -154,11 +143,7 @@ fn compile<'a>(
} }
} }
fn prompt_for_completion( fn prompt_for_completion(exercise: &Exercise, prompt_output: Option<String>, success_hints: bool) -> bool {
exercise: &Exercise,
prompt_output: Option<String>,
success_hints: bool,
) -> bool {
let context = match exercise.state() { let context = match exercise.state() {
State::Done => return true, State::Done => return true,
State::Pending(context) => context, State::Pending(context) => context,

View File

@ -44,7 +44,7 @@ fn verify_fails_if_some_fails() {
fn run_single_compile_success() { fn run_single_compile_success() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "compSuccess"]) .args(&["run", "compSuccess"])
.current_dir("tests/fixture/success/") .current_dir("tests/fixture/success/")
.assert() .assert()
.success(); .success();
@ -54,7 +54,7 @@ fn run_single_compile_success() {
fn run_single_compile_failure() { fn run_single_compile_failure() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "compFailure"]) .args(&["run", "compFailure"])
.current_dir("tests/fixture/failure/") .current_dir("tests/fixture/failure/")
.assert() .assert()
.code(1); .code(1);
@ -64,7 +64,7 @@ fn run_single_compile_failure() {
fn run_single_test_success() { fn run_single_test_success() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "testSuccess"]) .args(&["run", "testSuccess"])
.current_dir("tests/fixture/success/") .current_dir("tests/fixture/success/")
.assert() .assert()
.success(); .success();
@ -74,7 +74,7 @@ fn run_single_test_success() {
fn run_single_test_failure() { fn run_single_test_failure() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "testFailure"]) .args(&["run", "testFailure"])
.current_dir("tests/fixture/failure/") .current_dir("tests/fixture/failure/")
.assert() .assert()
.code(1); .code(1);
@ -84,7 +84,7 @@ fn run_single_test_failure() {
fn run_single_test_not_passed() { fn run_single_test_not_passed() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "testNotPassed.rs"]) .args(&["run", "testNotPassed.rs"])
.current_dir("tests/fixture/failure/") .current_dir("tests/fixture/failure/")
.assert() .assert()
.code(1); .code(1);
@ -97,17 +97,14 @@ fn run_single_test_no_filename() {
.arg("run") .arg("run")
.current_dir("tests/fixture/") .current_dir("tests/fixture/")
.assert() .assert()
.code(2) .code(1);
.stderr(predicates::str::contains(
"required arguments were not provided",
));
} }
#[test] #[test]
fn run_single_test_no_exercise() { fn run_single_test_no_exercise() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "compNoExercise.rs"]) .args(&["run", "compNoExercise.rs"])
.current_dir("tests/fixture/failure") .current_dir("tests/fixture/failure")
.assert() .assert()
.code(1); .code(1);
@ -117,7 +114,7 @@ fn run_single_test_no_exercise() {
fn reset_single_exercise() { fn reset_single_exercise() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["reset", "intro1"]) .args(&["reset", "intro1"])
.assert() .assert()
.code(0); .code(0);
} }
@ -128,9 +125,9 @@ fn reset_no_exercise() {
.unwrap() .unwrap()
.arg("reset") .arg("reset")
.assert() .assert()
.code(2) .code(1)
.stderr(predicates::str::contains( .stderr(predicates::str::contains(
"required arguments were not provided", "positional arguments not provided",
)); ));
} }
@ -138,7 +135,7 @@ fn reset_no_exercise() {
fn get_hint_for_single_test() { fn get_hint_for_single_test() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["hint", "testFailure"]) .args(&["hint", "testFailure"])
.current_dir("tests/fixture/failure") .current_dir("tests/fixture/failure")
.assert() .assert()
.code(0) .code(0)
@ -174,7 +171,7 @@ fn all_exercises_require_confirmation() {
fn run_compile_exercise_does_not_prompt() { fn run_compile_exercise_does_not_prompt() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "pending_exercise"]) .args(&["run", "pending_exercise"])
.current_dir("tests/fixture/state") .current_dir("tests/fixture/state")
.assert() .assert()
.code(0) .code(0)
@ -185,7 +182,7 @@ fn run_compile_exercise_does_not_prompt() {
fn run_test_exercise_does_not_prompt() { fn run_test_exercise_does_not_prompt() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "pending_test_exercise"]) .args(&["run", "pending_test_exercise"])
.current_dir("tests/fixture/state") .current_dir("tests/fixture/state")
.assert() .assert()
.code(0) .code(0)
@ -196,7 +193,7 @@ fn run_test_exercise_does_not_prompt() {
fn run_single_test_success_with_output() { fn run_single_test_success_with_output() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["--nocapture", "run", "testSuccess"]) .args(&["--nocapture", "run", "testSuccess"])
.current_dir("tests/fixture/success/") .current_dir("tests/fixture/success/")
.assert() .assert()
.code(0) .code(0)
@ -207,7 +204,7 @@ fn run_single_test_success_with_output() {
fn run_single_test_success_without_output() { fn run_single_test_success_without_output() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["run", "testSuccess"]) .args(&["run", "testSuccess"])
.current_dir("tests/fixture/success/") .current_dir("tests/fixture/success/")
.assert() .assert()
.code(0) .code(0)
@ -218,7 +215,7 @@ fn run_single_test_success_without_output() {
fn run_rustlings_list() { fn run_rustlings_list() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["list"]) .args(&["list"])
.current_dir("tests/fixture/success") .current_dir("tests/fixture/success")
.assert() .assert()
.success(); .success();
@ -228,7 +225,7 @@ fn run_rustlings_list() {
fn run_rustlings_list_no_pending() { fn run_rustlings_list_no_pending() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["list"]) .args(&["list"])
.current_dir("tests/fixture/success") .current_dir("tests/fixture/success")
.assert() .assert()
.success() .success()
@ -239,7 +236,7 @@ fn run_rustlings_list_no_pending() {
fn run_rustlings_list_both_done_and_pending() { fn run_rustlings_list_both_done_and_pending() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["list"]) .args(&["list"])
.current_dir("tests/fixture/state") .current_dir("tests/fixture/state")
.assert() .assert()
.success() .success()
@ -250,7 +247,7 @@ fn run_rustlings_list_both_done_and_pending() {
fn run_rustlings_list_without_pending() { fn run_rustlings_list_without_pending() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["list", "--solved"]) .args(&["list", "--solved"])
.current_dir("tests/fixture/state") .current_dir("tests/fixture/state")
.assert() .assert()
.success() .success()
@ -261,7 +258,7 @@ fn run_rustlings_list_without_pending() {
fn run_rustlings_list_without_done() { fn run_rustlings_list_without_done() {
Command::cargo_bin("rustlings") Command::cargo_bin("rustlings")
.unwrap() .unwrap()
.args(["list", "--unsolved"]) .args(&["list", "--unsolved"])
.current_dir("tests/fixture/state") .current_dir("tests/fixture/state")
.assert() .assert()
.success() .success()