mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-01-12 21:59:18 +00:00
Merge branch 'main' of https://github.com/bahamoth/rustlings
This commit is contained in:
commit
ca5ef17f41
@ -1488,6 +1488,60 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "nico-vromans",
|
||||||
|
"name": "Nico Vromans",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/48183857?v=4",
|
||||||
|
"profile": "https://github.com/nico-vromans",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "vostok92",
|
||||||
|
"name": "vostok92",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/540339?v=4",
|
||||||
|
"profile": "https://github.com/vostok92",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "magnusrodseth",
|
||||||
|
"name": "Magnus Rødseth",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/59113973?v=4",
|
||||||
|
"profile": "http://magnusrodseth.vercel.app",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "rubiesonthesky",
|
||||||
|
"name": "rubiesonthesky",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/2591240?v=4",
|
||||||
|
"profile": "https://github.com/rubiesonthesky",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "GabrielBianconi",
|
||||||
|
"name": "Gabriel Bianconi",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/1275491?v=4",
|
||||||
|
"profile": "http://www.gabrielbianconi.com/",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Kodylow",
|
||||||
|
"name": "Kody Low",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/74332828?v=4",
|
||||||
|
"profile": "https://github.com/Kodylow",
|
||||||
|
"contributions": [
|
||||||
|
"content"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 8,
|
"contributorsPerLine": 8,
|
||||||
|
|||||||
@ -212,6 +212,12 @@ authors.
|
|||||||
<tr>
|
<tr>
|
||||||
<td align="center"><a href="http://fakhoury.xyz"><img src="https://avatars.githubusercontent.com/u/20828724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brian Fakhoury</b></sub></a><br /><a href="#content-brianfakhoury" title="Content">🖋</a></td>
|
<td align="center"><a href="http://fakhoury.xyz"><img src="https://avatars.githubusercontent.com/u/20828724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brian Fakhoury</b></sub></a><br /><a href="#content-brianfakhoury" title="Content">🖋</a></td>
|
||||||
<td align="center"><a href="https://github.com/markusboehme"><img src="https://avatars.githubusercontent.com/u/5074759?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Markus Boehme</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=markusboehme" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/markusboehme"><img src="https://avatars.githubusercontent.com/u/5074759?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Markus Boehme</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=markusboehme" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/nico-vromans"><img src="https://avatars.githubusercontent.com/u/48183857?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nico Vromans</b></sub></a><br /><a href="#content-nico-vromans" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/vostok92"><img src="https://avatars.githubusercontent.com/u/540339?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vostok92</b></sub></a><br /><a href="#content-vostok92" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="http://magnusrodseth.vercel.app"><img src="https://avatars.githubusercontent.com/u/59113973?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Magnus Rødseth</b></sub></a><br /><a href="#content-magnusrodseth" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/rubiesonthesky"><img src="https://avatars.githubusercontent.com/u/2591240?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rubiesonthesky</b></sub></a><br /><a href="#content-rubiesonthesky" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="http://www.gabrielbianconi.com/"><img src="https://avatars.githubusercontent.com/u/1275491?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gabriel Bianconi</b></sub></a><br /><a href="#content-GabrielBianconi" title="Content">🖋</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Kodylow"><img src="https://avatars.githubusercontent.com/u/74332828?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kody Low</b></sub></a><br /><a href="#content-Kodylow" title="Content">🖋</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
59
CHANGELOG.md
59
CHANGELOG.md
@ -1,3 +1,62 @@
|
|||||||
|
<a name="5.2.0"></a>
|
||||||
|
## 5.2.0 (2022-08-27)
|
||||||
|
|
||||||
|
#### Added
|
||||||
|
|
||||||
|
- Added a `reset` command
|
||||||
|
|
||||||
|
#### Changed
|
||||||
|
|
||||||
|
- **options2**: Convert the exercise to use tests
|
||||||
|
|
||||||
|
#### Fixed
|
||||||
|
|
||||||
|
- **threads3**: Fixed a typo
|
||||||
|
- **quiz1**: Adjusted the explanations to be consistent with
|
||||||
|
the tests
|
||||||
|
|
||||||
|
<a name="5.1.1"></a>
|
||||||
|
## 5.1.1 (2022-08-17)
|
||||||
|
|
||||||
|
#### Bug Fixes
|
||||||
|
|
||||||
|
- Fixed an incorrect assertion in options1
|
||||||
|
|
||||||
|
<a name="5.1.0"></a>
|
||||||
|
## 5.1.0 (2022-08-16)
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
|
||||||
|
- Added a new `rc1` exercise.
|
||||||
|
- Added a new `cow1` exercise.
|
||||||
|
|
||||||
|
#### Bug Fixes
|
||||||
|
|
||||||
|
- **variables5**: Corrected reference to previous exercise
|
||||||
|
- **functions4**: Fixed line number reference
|
||||||
|
- **strings3**: Clarified comment wording
|
||||||
|
- **traits4, traits5**: Fixed line number reference
|
||||||
|
- **traits5**:
|
||||||
|
- Fixed typo in "parameter"
|
||||||
|
- Made exercise prefer a traits-based solution
|
||||||
|
- **lifetimes2**: Improved hint
|
||||||
|
- **threads3**: Fixed typo in hint
|
||||||
|
- **box1**: Replaced `unimplemented!` with `todo!`
|
||||||
|
- **errors5**: Provided an explanation for usage of `Box<dyn Error>`
|
||||||
|
- **quiz2**: Fixed a typo
|
||||||
|
- **macros**: Updated the macros book link
|
||||||
|
- **options1**:
|
||||||
|
- Removed unused code
|
||||||
|
- Added more granular tests
|
||||||
|
- Fixed some comment syntax shenanigans in info.toml
|
||||||
|
|
||||||
|
#### Housekeeping
|
||||||
|
|
||||||
|
- Fixed a typo in .editorconfig
|
||||||
|
- Fixed a typo in integration_tests.rs
|
||||||
|
- Clarified manual installation instructions using `cargo install --path .`
|
||||||
|
- Added a link to our Zulip in the readme file
|
||||||
|
|
||||||
<a name="5.0.0"></a>
|
<a name="5.0.0"></a>
|
||||||
## 5.0.0 (2022-07-16)
|
## 5.0.0 (2022-07-16)
|
||||||
|
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -459,7 +459,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
version = "5.0.0"
|
version = "5.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argh",
|
"argh",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
version = "5.0.0"
|
version = "5.2.0"
|
||||||
authors = ["Liv <mokou@fastmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
authors = ["Liv <mokou@fastmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@ -57,8 +57,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.0.0)
|
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.1.1)
|
||||||
git clone -b 5.0.0 --depth 1 https://github.com/rust-lang/rustlings
|
git clone -b 5.1.1 --depth 1 https://github.com/rust-lang/rustlings
|
||||||
cd rustlings
|
cd rustlings
|
||||||
cargo install --force --path .
|
cargo install --force --path .
|
||||||
```
|
```
|
||||||
@ -154,6 +154,10 @@ Now you should be done!
|
|||||||
|
|
||||||
See [CONTRIBUTING.md](./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](./AUTHORS.md) 🎉
|
Thanks goes to the wonderful people listed in [AUTHORS.md](./AUTHORS.md) 🎉
|
||||||
|
|||||||
@ -19,6 +19,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_icecream() {
|
fn check_icecream() {
|
||||||
|
assert_eq!(maybe_icecream(9), Some(5));
|
||||||
assert_eq!(maybe_icecream(10), Some(5));
|
assert_eq!(maybe_icecream(10), Some(5));
|
||||||
assert_eq!(maybe_icecream(23), Some(0));
|
assert_eq!(maybe_icecream(23), Some(0));
|
||||||
assert_eq!(maybe_icecream(22), Some(0));
|
assert_eq!(maybe_icecream(22), Some(0));
|
||||||
|
|||||||
@ -3,23 +3,34 @@
|
|||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
fn main() {
|
#[cfg(test)]
|
||||||
let optional_word = Some(String::from("rustlings"));
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_option() {
|
||||||
|
let target = "rustlings";
|
||||||
|
let optional_target = Some(target);
|
||||||
|
|
||||||
// TODO: Make this an if let statement whose value is "Some" type
|
// TODO: Make this an if let statement whose value is "Some" type
|
||||||
word = optional_word {
|
word = optional_target {
|
||||||
println!("The word is: {}", word);
|
assert_eq!(word, target);
|
||||||
} else {
|
}
|
||||||
println!("The optional word doesn't contain anything");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
|
#[test]
|
||||||
for x in 1..10 {
|
fn layered_option() {
|
||||||
optional_integers_vec.push(Some(x));
|
let mut range = 10;
|
||||||
|
let mut optional_integers: Vec<Option<i8>> = Vec::new();
|
||||||
|
for i in 0..(range + 1) {
|
||||||
|
optional_integers.push(Some(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
|
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
|
||||||
// You can stack `Option<T>`'s into while let and if let
|
// You can stack `Option<T>`'s into while let and if let
|
||||||
integer = optional_integers_vec.pop() {
|
integer = optional_integers.pop() {
|
||||||
println!("current value: {}", integer);
|
assert_eq!(integer, range);
|
||||||
|
range -= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
// - If
|
// - If
|
||||||
|
|
||||||
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
|
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
|
||||||
// more than 40 at once, each apple only costs 1! Write a function that calculates
|
// 40 or more at once, each apple only costs 1! Write a function that calculates
|
||||||
// the price of an order of apples given the quantity bought. No hints this time!
|
// the price of an order of apples given the quantity bought. No hints this time!
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|||||||
48
exercises/standard_library_types/cow1.rs
Normal file
48
exercises/standard_library_types/cow1.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// cow1.rs
|
||||||
|
|
||||||
|
// This exercise explores the Cow, or Clone-On-Write type.
|
||||||
|
// Cow is a clone-on-write smart pointer.
|
||||||
|
// It can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required.
|
||||||
|
// The type is designed to work with general borrowed data via the Borrow trait.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> {
|
||||||
|
for i in 0..input.len() {
|
||||||
|
let v = input[i];
|
||||||
|
if v < 0 {
|
||||||
|
// Clones into a vector if not already owned.
|
||||||
|
input.to_mut()[i] = -v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// No clone occurs because `input` doesn't need to be mutated.
|
||||||
|
let slice = [0, 1, 2];
|
||||||
|
let mut input = Cow::from(&slice[..]);
|
||||||
|
match abs_all(&mut input) {
|
||||||
|
Cow::Borrowed(_) => println!("I borrowed the slice!"),
|
||||||
|
_ => panic!("expected borrowed value"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone occurs because `input` needs to be mutated.
|
||||||
|
let slice = [-1, 0, 1];
|
||||||
|
let mut input = Cow::from(&slice[..]);
|
||||||
|
match abs_all(&mut input) {
|
||||||
|
Cow::Owned(_) => println!("I modified the slice and now own it!"),
|
||||||
|
_ => panic!("expected owned value"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// No clone occurs because `input` is already owned.
|
||||||
|
let slice = vec![-1, 0, 1];
|
||||||
|
let mut input = Cow::from(slice);
|
||||||
|
match abs_all(&mut input) {
|
||||||
|
// TODO
|
||||||
|
Cow::Borrowed(_) => println!("I own this slice!"),
|
||||||
|
_ => panic!("expected borrowed value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
98
exercises/standard_library_types/rc1.rs
Normal file
98
exercises/standard_library_types/rc1.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// rc1.rs
|
||||||
|
// In this exercise, we want to express the concept of multiple owners via the Rc<T> type.
|
||||||
|
// This is a model of our solar system - there is a Sun type and multiple Planets.
|
||||||
|
// The Planets take ownership of the sun, indicating that they revolve around the sun.
|
||||||
|
|
||||||
|
// Make this code compile by using the proper Rc primitives to express that the sun has multiple owners.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Sun {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Planet {
|
||||||
|
Mercury(Rc<Sun>),
|
||||||
|
Venus(Rc<Sun>),
|
||||||
|
Earth(Rc<Sun>),
|
||||||
|
Mars(Rc<Sun>),
|
||||||
|
Jupiter(Rc<Sun>),
|
||||||
|
Saturn(Rc<Sun>),
|
||||||
|
Uranus(Rc<Sun>),
|
||||||
|
Neptune(Rc<Sun>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Planet {
|
||||||
|
fn details(&self) {
|
||||||
|
println!("Hi from {:?}!", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let sun = Rc::new(Sun {});
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
|
||||||
|
|
||||||
|
let mercury = Planet::Mercury(Rc::clone(&sun));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
|
||||||
|
mercury.details();
|
||||||
|
|
||||||
|
let venus = Planet::Venus(Rc::clone(&sun));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
|
||||||
|
venus.details();
|
||||||
|
|
||||||
|
let earth = Planet::Earth(Rc::clone(&sun));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
|
||||||
|
earth.details();
|
||||||
|
|
||||||
|
let mars = Planet::Mars(Rc::clone(&sun));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
|
||||||
|
mars.details();
|
||||||
|
|
||||||
|
let jupiter = Planet::Jupiter(Rc::clone(&sun));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
|
||||||
|
jupiter.details();
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
let saturn = Planet::Saturn(Rc::new(Sun {}));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
|
||||||
|
saturn.details();
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
let uranus = Planet::Uranus(Rc::new(Sun {}));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
|
||||||
|
uranus.details();
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
let neptune = Planet::Neptune(Rc::new(Sun {}));
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
|
||||||
|
neptune.details();
|
||||||
|
|
||||||
|
assert_eq!(Rc::strong_count(&sun), 9);
|
||||||
|
|
||||||
|
drop(neptune);
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
|
||||||
|
|
||||||
|
drop(uranus);
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
|
||||||
|
|
||||||
|
drop(saturn);
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
|
||||||
|
|
||||||
|
drop(jupiter);
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
|
||||||
|
|
||||||
|
drop(mars);
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
|
||||||
|
|
||||||
|
assert_eq!(Rc::strong_count(&sun), 1);
|
||||||
|
}
|
||||||
29
info.toml
29
info.toml
@ -545,7 +545,7 @@ is the easiest, but how do you do it safely so that it doesn't panic in your fac
|
|||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "options2"
|
name = "options2"
|
||||||
path = "exercises/options/options2.rs"
|
path = "exercises/options/options2.rs"
|
||||||
mode = "compile"
|
mode = "test"
|
||||||
hint = """
|
hint = """
|
||||||
check out:
|
check out:
|
||||||
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
|
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
|
||||||
@ -932,6 +932,31 @@ is too much of a struggle, consider reading through all of Chapter 16 in the boo
|
|||||||
https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html
|
https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
[[exercises]]
|
||||||
|
name = "rc1"
|
||||||
|
path = "exercises/standard_library_types/rc1.rs"
|
||||||
|
mode = "compile"
|
||||||
|
hint = """
|
||||||
|
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.
|
||||||
|
After using drop() to move the Planets out of scope individually, the reference count goes down.
|
||||||
|
In the end the sun only has one reference again, to itself. See more at:
|
||||||
|
https://doc.rust-lang.org/book/ch15-04-rc.html
|
||||||
|
|
||||||
|
* Unforunately Pluto is no longer considered a planet :(
|
||||||
|
"""
|
||||||
|
|
||||||
|
[[exercises]]
|
||||||
|
name = "cow1"
|
||||||
|
path = "exercises/standard_library_types/cow1.rs"
|
||||||
|
mode = "compile"
|
||||||
|
hint = """
|
||||||
|
Since the vector is already owned, the `Cow` type doesn't need to clone it.
|
||||||
|
|
||||||
|
Checkout https://doc.rust-lang.org/std/borrow/enum.Cow.html for documentation
|
||||||
|
on the `Cow` type.
|
||||||
|
"""
|
||||||
|
|
||||||
# THREADS
|
# THREADS
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
@ -987,7 +1012,7 @@ 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.
|
||||||
With both a sending end and a receiving end, it's possible to
|
With both a sending end and a receiving end, it's possible to
|
||||||
send values in one thread and receieve them in another.
|
send values in one thread and receive them in another.
|
||||||
Multiple producers are possible by using clone() to create a duplicate
|
Multiple producers are possible by using clone() to create a duplicate
|
||||||
of the original sending end.
|
of the original sending end.
|
||||||
See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info.
|
See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info.
|
||||||
|
|||||||
63
src/main.rs
63
src/main.rs
@ -1,6 +1,6 @@
|
|||||||
use crate::exercise::{Exercise, ExerciseList};
|
use crate::exercise::{Exercise, ExerciseList};
|
||||||
use crate::project::RustAnalyzerProject;
|
use crate::project::RustAnalyzerProject;
|
||||||
use crate::run::run;
|
use crate::run::{reset, run};
|
||||||
use crate::verify::verify;
|
use crate::verify::verify;
|
||||||
use argh::FromArgs;
|
use argh::FromArgs;
|
||||||
use console::Emoji;
|
use console::Emoji;
|
||||||
@ -26,7 +26,7 @@ mod run;
|
|||||||
mod verify;
|
mod verify;
|
||||||
|
|
||||||
// In sync with crate version
|
// In sync with crate version
|
||||||
const VERSION: &str = "5.0.0";
|
const VERSION: &str = "5.2.0";
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[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
|
||||||
@ -47,6 +47,7 @@ enum Subcommands {
|
|||||||
Verify(VerifyArgs),
|
Verify(VerifyArgs),
|
||||||
Watch(WatchArgs),
|
Watch(WatchArgs),
|
||||||
Run(RunArgs),
|
Run(RunArgs),
|
||||||
|
Reset(ResetArgs),
|
||||||
Hint(HintArgs),
|
Hint(HintArgs),
|
||||||
List(ListArgs),
|
List(ListArgs),
|
||||||
Lsp(LspArgs),
|
Lsp(LspArgs),
|
||||||
@ -71,6 +72,15 @@ struct RunArgs {
|
|||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
#[argh(subcommand, name = "reset")]
|
||||||
|
/// Resets a single exercise using "git stash -- <filename>"
|
||||||
|
struct ResetArgs {
|
||||||
|
#[argh(positional)]
|
||||||
|
/// the name of the exercise
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand, name = "hint")]
|
#[argh(subcommand, name = "hint")]
|
||||||
/// Returns a hint for the given exercise
|
/// Returns a hint for the given exercise
|
||||||
@ -85,7 +95,6 @@ struct HintArgs {
|
|||||||
/// Enable rust-analyzer for exercises
|
/// Enable rust-analyzer for exercises
|
||||||
struct LspArgs {}
|
struct LspArgs {}
|
||||||
|
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand, name = "list")]
|
#[argh(subcommand, name = "list")]
|
||||||
/// Lists the exercises available in Rustlings
|
/// Lists the exercises available in Rustlings
|
||||||
@ -164,7 +173,9 @@ fn main() {
|
|||||||
"Pending"
|
"Pending"
|
||||||
};
|
};
|
||||||
let solve_cond = {
|
let solve_cond = {
|
||||||
(e.looks_done() && subargs.solved) || (!e.looks_done() && subargs.unsolved) || (!subargs.solved && !subargs.unsolved)
|
(e.looks_done() && subargs.solved)
|
||||||
|
|| (!e.looks_done() && subargs.unsolved)
|
||||||
|
|| (!subargs.solved && !subargs.unsolved)
|
||||||
};
|
};
|
||||||
if solve_cond && (filter_cond || subargs.filter.is_none()) {
|
if solve_cond && (filter_cond || subargs.filter.is_none()) {
|
||||||
let line = if subargs.paths {
|
let line = if subargs.paths {
|
||||||
@ -205,6 +216,12 @@ fn main() {
|
|||||||
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
|
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Subcommands::Reset(subargs) => {
|
||||||
|
let exercise = find_exercise(&subargs.name, &exercises);
|
||||||
|
|
||||||
|
reset(exercise).unwrap_or_else(|_| std::process::exit(1));
|
||||||
|
}
|
||||||
|
|
||||||
Subcommands::Hint(subargs) => {
|
Subcommands::Hint(subargs) => {
|
||||||
let exercise = find_exercise(&subargs.name, &exercises);
|
let exercise = find_exercise(&subargs.name, &exercises);
|
||||||
|
|
||||||
@ -212,7 +229,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Subcommands::Verify(_subargs) => {
|
Subcommands::Verify(_subargs) => {
|
||||||
verify(&exercises, (0, exercises.len()), verbose).unwrap_or_else(|_| std::process::exit(1));
|
verify(&exercises, (0, exercises.len()), verbose)
|
||||||
|
.unwrap_or_else(|_| std::process::exit(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Subcommands::Lsp(_subargs) => {
|
Subcommands::Lsp(_subargs) => {
|
||||||
@ -236,12 +254,18 @@ fn main() {
|
|||||||
|
|
||||||
Subcommands::Watch(_subargs) => match watch(&exercises, verbose) {
|
Subcommands::Watch(_subargs) => match watch(&exercises, verbose) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error: Could not watch your progress. Error message was {:?}.", e);
|
println!(
|
||||||
|
"Error: Could not watch your progress. Error message was {:?}.",
|
||||||
|
e
|
||||||
|
);
|
||||||
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
|
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
Ok(WatchStatus::Finished) => {
|
Ok(WatchStatus::Finished) => {
|
||||||
println!("{emoji} All exercises completed! {emoji}", emoji = Emoji("🎉", "★"));
|
println!(
|
||||||
|
"{emoji} All exercises completed! {emoji}",
|
||||||
|
emoji = Emoji("🎉", "★")
|
||||||
|
);
|
||||||
println!("\n{}\n", FENISH_LINE);
|
println!("\n{}\n", FENISH_LINE);
|
||||||
}
|
}
|
||||||
Ok(WatchStatus::Unfinished) => {
|
Ok(WatchStatus::Unfinished) => {
|
||||||
@ -252,8 +276,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_watch_shell(
|
||||||
fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_quit: Arc<AtomicBool>) {
|
failed_exercise_hint: &Arc<Mutex<Option<String>>>,
|
||||||
|
should_quit: Arc<AtomicBool>,
|
||||||
|
) {
|
||||||
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
|
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
|
||||||
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
|
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
@ -290,13 +316,19 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_q
|
|||||||
|
|
||||||
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
|
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
|
||||||
if name.eq("next") {
|
if name.eq("next") {
|
||||||
exercises.iter().find(|e| !e.looks_done()).unwrap_or_else(|| {
|
exercises
|
||||||
|
.iter()
|
||||||
|
.find(|e| !e.looks_done())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
println!("🎉 Congratulations! You have done all the exercises!");
|
println!("🎉 Congratulations! You have done all the exercises!");
|
||||||
println!("🔚 There are no more exercises to do next!");
|
println!("🔚 There are no more exercises to do next!");
|
||||||
std::process::exit(1)
|
std::process::exit(1)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
exercises.iter().find(|e| e.name == name).unwrap_or_else(|| {
|
exercises
|
||||||
|
.iter()
|
||||||
|
.find(|e| e.name == name)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
println!("No exercise found for '{}'!", name);
|
println!("No exercise found for '{}'!", name);
|
||||||
std::process::exit(1)
|
std::process::exit(1)
|
||||||
})
|
})
|
||||||
@ -337,8 +369,13 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<WatchStatus> {
|
|||||||
let filepath = b.as_path().canonicalize().unwrap();
|
let filepath = b.as_path().canonicalize().unwrap();
|
||||||
let pending_exercises = exercises
|
let pending_exercises = exercises
|
||||||
.iter()
|
.iter()
|
||||||
.find(|e| filepath.ends_with(&e.path)).into_iter()
|
.find(|e| filepath.ends_with(&e.path))
|
||||||
.chain(exercises.iter().filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)));
|
.into_iter()
|
||||||
|
.chain(
|
||||||
|
exercises
|
||||||
|
.iter()
|
||||||
|
.filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
|
||||||
|
);
|
||||||
let num_done = exercises.iter().filter(|e| e.looks_done()).count();
|
let num_done = exercises.iter().filter(|e| e.looks_done()).count();
|
||||||
clear_screen();
|
clear_screen();
|
||||||
match verify(pending_exercises, (num_done, exercises.len()), verbose) {
|
match verify(pending_exercises, (num_done, exercises.len()), verbose) {
|
||||||
|
|||||||
15
src/run.rs
15
src/run.rs
@ -1,3 +1,5 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use crate::exercise::{Exercise, Mode};
|
use crate::exercise::{Exercise, Mode};
|
||||||
use crate::verify::test;
|
use crate::verify::test;
|
||||||
use indicatif::ProgressBar;
|
use indicatif::ProgressBar;
|
||||||
@ -15,6 +17,19 @@ pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resets the exercise by stashing the changes.
|
||||||
|
pub fn reset(exercise: &Exercise) -> Result<(), ()> {
|
||||||
|
let command = Command::new("git")
|
||||||
|
.args(["stash", "--"])
|
||||||
|
.arg(&exercise.path)
|
||||||
|
.spawn();
|
||||||
|
|
||||||
|
match command {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Invoke the rust compiler on the path of the given exercise
|
// Invoke the rust compiler on the path of the given exercise
|
||||||
// and run the ensuing binary.
|
// and run the ensuing binary.
|
||||||
// This is strictly for non-test binaries, so output is displayed
|
// This is strictly for non-test binaries, so output is displayed
|
||||||
|
|||||||
@ -110,6 +110,27 @@ fn run_single_test_no_exercise() {
|
|||||||
.code(1);
|
.code(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reset_single_exercise() {
|
||||||
|
Command::cargo_bin("rustlings")
|
||||||
|
.unwrap()
|
||||||
|
.args(&["reset", "intro1"])
|
||||||
|
.assert()
|
||||||
|
.code(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reset_no_exercise() {
|
||||||
|
Command::cargo_bin("rustlings")
|
||||||
|
.unwrap()
|
||||||
|
.arg("reset")
|
||||||
|
.assert()
|
||||||
|
.code(1)
|
||||||
|
.stderr(predicates::str::contains(
|
||||||
|
"positional arguments not provided",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_hint_for_single_test() {
|
fn get_hint_for_single_test() {
|
||||||
Command::cargo_bin("rustlings")
|
Command::cargo_bin("rustlings")
|
||||||
@ -126,7 +147,7 @@ fn all_exercises_require_confirmation() {
|
|||||||
for exercise in glob("exercises/**/*.rs").unwrap() {
|
for exercise in glob("exercises/**/*.rs").unwrap() {
|
||||||
let path = exercise.unwrap();
|
let path = exercise.unwrap();
|
||||||
if path.file_name().unwrap() == "mod.rs" {
|
if path.file_name().unwrap() == "mod.rs" {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
let source = {
|
let source = {
|
||||||
let mut file = File::open(&path).unwrap();
|
let mut file = File::open(&path).unwrap();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user