Compare commits

...

42 Commits

Author SHA1 Message Date
7a1ca00837 solution to exercise 04_05 2024-07-13 17:39:46 +02:00
1789d43730 solution to exercise 04_04 2024-07-13 17:30:01 +02:00
604a5a20ae solution to exercise 04_03 2024-07-01 16:30:43 +02:00
0829174983 solution to exercise 04_02 2024-07-01 16:23:02 +02:00
ebe07acd1e solution to exercise 04_01 2024-07-01 16:15:42 +02:00
4a4fc2ea0d solution to exercise 03_12 2024-06-27 16:38:30 +02:00
91e6bf5ae4 solution to exercise 03_11 2024-06-27 16:29:31 +02:00
3f57819e4c solution to exercise 03_10 2024-06-27 16:24:32 +02:00
d54a1e160b solution to exercise 03_09 2024-06-27 16:16:19 +02:00
4913da035f solution to exercise 03_08 2024-06-27 16:08:42 +02:00
1f0823a6a4 solution to exercise 03_07 2024-06-23 18:22:03 +02:00
56075fa40e solution to exercise 03_06 2024-06-23 18:08:59 +02:00
852cd5f0b9 solution to exercise 03_05 2024-06-23 17:58:03 +02:00
1c16ac8c22 solution to exercise 03_04 2024-06-23 17:54:39 +02:00
d3b4c0d653 solution to exercise 03_03 2024-06-19 15:03:51 +02:00
8b78ea3a83 solution to exercise 03_02 2024-06-19 14:56:36 +02:00
0e5cdc6d10 solution to exercise 03_01 2024-06-19 14:46:00 +02:00
1d876eff10 solution to exercise 03_00 2024-06-19 14:41:41 +02:00
dfcb9736b2 solution to exercise 02_10 2024-06-17 11:31:06 +02:00
c1e7c3fadd solution to exercise 02_09 2024-06-17 11:22:25 +02:00
978a99b00d solution to exercise 02_08 2024-06-17 11:15:21 +02:00
34189d212e solution to exercise 02_07 2024-06-17 10:59:03 +02:00
9d1869fc9c solution to exercise 02_06 2024-06-17 10:53:22 +02:00
3e56cf1287 solution to exercise 02_05 2024-06-15 21:01:03 +02:00
f91cc0089a solution to exercise 02_04 2024-06-13 17:04:21 +02:00
211f23cea4 solution to exercise 02_03 2024-06-13 16:55:06 +02:00
1e516bf0a5 solution to exercise 02_02 2024-06-13 16:46:44 +02:00
03a0a77394 solution to exercise 02_01 2024-06-13 16:40:40 +02:00
bb27bfad41 solution to exercise 02_00 2024-06-13 16:33:07 +02:00
4d12facc2f solution to exercise 01 2024-06-12 17:12:56 +02:00
1251a6c1b1 solution to exercise 00 2024-06-12 17:06:43 +02:00
Felix Pherry
056611ac1c Fix: typos (#84)
Co-authored-by: Felix Pherry <182051.FELIX@klgroup.local>
2024-06-05 11:59:04 +02:00
Felix Pherry
e99a15390e fix(book): Correct type parameter naming convention to pascal case (#79)
* fix(book): Correct type parameter naming convention to pascal case

* Update book/src/04_traits/05_trait_bounds.md

---------

Co-authored-by: Felix Pherry <182051.FELIX@klgroup.local>
Co-authored-by: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com>
2024-06-01 08:31:48 +02:00
rithvik-bosch
ffb2f08b67 nit: grammar (#70) 2024-05-29 10:59:32 +02:00
LukeMathWalker
baca47f782 Add a TODO to make things more explicit. 2024-05-28 11:18:27 +02:00
LukeMathWalker
d442b61795 Reword. 2024-05-28 11:11:41 +02:00
Keshav Chakravarthy
d77272a5b4 Better example for ownership transfer using String (#68)
* Better example for ownership transfer using String

* Update book/src/03_ticket_v1/06_ownership.md

---------

Co-authored-by: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com>
2024-05-28 11:08:34 +02:00
Ernie Hershey
deb4ccb643 Grammar typo (#65) 2024-05-28 11:05:59 +02:00
Onè
35a2ff1efe Change execution unit name (#60) 2024-05-28 11:05:46 +02:00
Shinya Fujino
5140cd3b37 Update variant name (#58) 2024-05-28 11:04:32 +02:00
Shinya Fujino
3020ef6c3f Fix a typo (#57) 2024-05-28 11:04:19 +02:00
Onè
f74fbd4800 typos (#55)
* Add missing of

* change tense of spawn

* ignored to ignoring

* add need
2024-05-28 11:04:08 +02:00
45 changed files with 259 additions and 84 deletions

View File

@@ -1,3 +1,6 @@
[workspace]
members = ["exercises/*/*", "helpers/common", "helpers/mdbook-exercise-linker", "helpers/ticket_fields"]
resolver = "2"
[profile.dev]
overflow-checks = false

View File

@@ -95,8 +95,8 @@ Ownership can be transferred.
If you own a value, for example, you can transfer ownership to another variable:
```rust
let a = 42; // <--- `a` is the owner of the value `42`
let b = a; // <--- `b` is now the owner of the value `42`
let a = "hello, world".to_string(); // <--- `a` is the owner of the String
let b = a; // <--- `b` is now the owner of the String
```
Rust's ownership system is baked into the type system: each function has to declare in its signature

View File

@@ -58,7 +58,7 @@ You've already encountered a few macros in past exercises:
Rust macros are **code generators**.\
They generate new Rust code based on the input you provide, and that generated code is then compiled alongside
the rest of your program. Some macros are built into Rust's standard library, but you can also
write your own. We won't be creating our macro in this course, but you can find some useful
write your own. We won't be creating our own macro in this course, but you can find some useful
pointers in the ["Further reading" section](#further-reading).
### Inspection

View File

@@ -58,7 +58,7 @@ We can do better using **generics**.\
Generics allow us to write code that works with a **type parameter** instead of a concrete type:
```rust
fn print_if_even<T>(n: T)
fn print_if_even<T>(n: T)
where
T: IsEven + Debug
{
@@ -125,7 +125,7 @@ body is present.
All the examples above used a **`where` clause** to specify trait bounds:
```rust
fn print_if_even<T>(n: T)
fn print_if_even<T>(n: T)
where
T: IsEven + Debug
// ^^^^^^^^^^^^^^^^^
@@ -160,7 +160,7 @@ fn print_if_even<Number: IsEven + Debug>(n: Number) {
It is actually **desirable** to use meaningful names when there are multiple type parameters at play or when the name
`T` doesn't convey enough information about the type's role in the function.
Maximize clarity and readability when naming type parameters, just as you would with variables or function parameters.
Follow Rust's conventions though: use camel case for type parameter names.
Follow Rust's conventions, though: use [upper camel case for type parameter names](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case).
## The function signature is king

View File

@@ -51,7 +51,7 @@ let y = point.1;
### Tuples
It's weird say that something is tuple-like when we haven't seen tuples yet!\
It's weird to say that something is tuple-like when we haven't seen tuples yet!\
Tuples are another example of a primitive Rust type.
They group together a fixed number of values with (potentially different) types:

View File

@@ -2,12 +2,12 @@
## Error reporting
In the previous exercise you had to destructure the `InvalidTitle` variant to extract the error message and
In the previous exercise you had to destructure the `TitleError` variant to extract the error message and
pass it to the `panic!` macro.\
This is a (rudimentary) example of **error reporting**: transforming an error type into a representation that can be
shown to a user, a service operator, or a developer.
It's not practical for each Rust developer to come up with their own error reporting strategy: it'd a waste of time
It's not practical for each Rust developer to come up with their own error reporting strategy: it'd be a waste of time
and it wouldn't compose well across projects.
That's why Rust provides the `std::error::Error` trait.

View File

@@ -66,7 +66,7 @@ assert_eq!(numbers.get(0), Some(&1));
assert_eq!(numbers.get(3), None);
```
Access is bounds-checked, just element access with arrays. It has O(1) complexity.
Access is bounds-checked, just like element access with arrays. It has O(1) complexity.
## Memory layout

View File

@@ -12,4 +12,4 @@ We'll have the opportunity to touch most of Rust's core concurrency features, in
- Shared state, using `Arc`, `Mutex` and `RwLock`
- `Send` and `Sync`, the traits that encode Rust's concurrency guarantees
We'll also discuss various design patterns for multithreaded systems and some their trade-offs.
We'll also discuss various design patterns for multithreaded systems and some of their trade-offs.

View File

@@ -74,7 +74,7 @@ struct TicketStore {
```
This approach is more efficient, but it has a downside: `TicketStore` has to become **aware** of the multithreaded
nature of the system; up until now, `TicketStore` has been blissfully ignored the existence of threads.\
nature of the system; up until now, `TicketStore` has been blissfully ignoring the existence of threads.\
Let's go for it anyway.
## Who holds the lock?

View File

@@ -48,7 +48,7 @@ If we remove the channels, we need to introduce (another) lock to synchronize ac
If we use a `Mutex`, then it makes no sense to use an additional `RwLock` for each ticket: the `Mutex` will
already serialize access to the entire store, so we wouldn't be able to read tickets in parallel anyway.\
If we use a `RwLock`, instead, we can read tickets in parallel. We just to pause all reads while inserting
If we use a `RwLock`, instead, we can read tickets in parallel. We just need to pause all reads while inserting
or removing a ticket.
Let's go down this path and see where it leads us.

View File

@@ -99,7 +99,7 @@ pub async fn run() {
if let Ok(reason) = e.try_into_panic() {
// The task has panicked
// We resume unwinding the panic,
// thus propagating it to the current thread
// thus propagating it to the current task
panic::resume_unwind(reason);
}
}

View File

@@ -28,8 +28,7 @@ project and on [exercism.io](https://exercism.io)'s Rust track.
Check out [the Rust book](https://doc.rust-lang.org/book/title-page.html) and
["Programming Rust"](https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/)
if you're looking for a different perspective on the same concepts we covered throughout this course.
The material doesn't overlap perfectly, therefore you'll certainly learn something new along the
way.
You'll certainly learn something new since they don't cover exactly the same topics; Rust has a lot of surface area!
### Advanced material

View File

@@ -17,7 +17,7 @@
// You can also find solutions to all exercises in the `solutions` git branch.
fn greeting() -> &'static str {
// TODO: fix me 👇
"I'm ready to __!"
"I'm ready to learn Rust!"
}
// Your solutions will be automatically verified by a set of tests.

View File

@@ -3,7 +3,7 @@
// partner in this course and it'll often guide you in the right direction!
//
// The input parameters should have the same type of the return type.
fn compute(a, b) -> u32 {
fn compute(a: u32, b: u32) -> u32 {
// Don't touch the function body.
a + b * 2
}
@@ -16,4 +16,4 @@ mod tests {
fn case() {
assert_eq!(compute(1, 2), 5);
}
}
}

View File

@@ -1,6 +1,6 @@
fn intro() -> &'static str {
// TODO: fix me 👇
"I'm ready to __!"
"I'm ready to build a calculator in Rust!"
}
#[cfg(test)]

View File

@@ -1,6 +1,6 @@
fn compute(a: u32, b: u32) -> u32 {
// TODO: change the line below to fix the compiler error and make the tests pass.
a + b * 4u8
a + b * 4u32
}
#[cfg(test)]

View File

@@ -8,7 +8,7 @@
pub fn speed(start: u32, end: u32, time_elapsed: u32) -> u32 {
// TODO: define a variable named `distance` with the right value to get tests to pass
// Do you need to annotate the type of `distance`? Why or why not?
let distance: u32 = end - start;
// Don't change the line below
distance / time_elapsed
}

View File

@@ -1,6 +1,6 @@
/// Return `true` if `n` is even, `false` otherwise.
fn is_even(n: u32) -> bool {
todo!()
n % 2 == 0
}
#[cfg(test)]

View File

@@ -2,7 +2,9 @@
/// calculate the average speed of the journey.
fn speed(start: u32, end: u32, time_elapsed: u32) -> u32 {
// TODO: Panic with a custom message if `time_elapsed` is 0
if time_elapsed == 0 {
panic!("The journey took no time at all, that's impossible!");
}
(end - start) / time_elapsed
}

View File

@@ -9,6 +9,13 @@
// `factorial(2)` to return `2`, and so on.
//
// Use only what you learned! No loops yet, so you'll have to use recursion!
fn factorial(n: u16) -> u16 {
if n == 0 {
1
} else {
n * factorial(n - 1)
}
}
#[cfg(test)]
mod tests {

View File

@@ -4,7 +4,13 @@ pub fn factorial(n: u32) -> u32 {
// interprets as "I'll get back to this later", thus
// suppressing type errors.
// It panics at runtime.
todo!()
let mut result: u32 = 1; // base case
let mut i: u32 = 1;
while i <= n {
result *= i;
i += 1;
}
result
}
#[cfg(test)]

View File

@@ -1,6 +1,10 @@
// Rewrite the factorial function using a `for` loop.
pub fn factorial(n: u32) -> u32 {
todo!()
let mut result: u32 = 1; // base case
for i in 2..=n {
result *= i;
}
result
}
#[cfg(test)]

View File

@@ -1,9 +1,9 @@
pub fn factorial(n: u32) -> u32 {
let mut result = 1;
let mut result: u32 = 1;
for i in 1..=n {
// Use saturating multiplication to stop at the maximum value of u32
// rather than overflowing and wrapping around
result *= i;
result = result.saturating_mul(i);
}
result
}

View File

@@ -6,7 +6,7 @@ mod tests {
#[test]
fn u16_to_u32() {
let v: u32 = todo!();
let v: u32 = 47;
assert_eq!(47u16 as u32, v);
}
@@ -24,14 +24,14 @@ mod tests {
// You could solve this by using exactly the same expression as above,
// but that would defeat the purpose of the exercise. Instead, use a genuine
// `i8` value that is equivalent to `255` when converted from `u8`.
let y: i8 = todo!();
let y: i8 = -1;
assert_eq!(x, y);
}
#[test]
fn bool_to_u8() {
let v: u8 = todo!();
let v: u8 = 1;
assert_eq!(true as u8, v);
}
}

View File

@@ -1,6 +1,6 @@
fn intro() -> &'static str {
// TODO: fix me 👇
"I'm ready to __!"
"I'm ready to start modelling a software ticket!"
}
#[cfg(test)]

View File

@@ -4,6 +4,16 @@
//
// It should also have a method named `is_available` that returns a `true` if the quantity is
// greater than 0, otherwise `false`.
struct Order {
price: u8,
quantity: u8,
}
impl Order {
fn is_available(self) -> bool {
self.quantity > 0
}
}
#[cfg(test)]
mod tests {

View File

@@ -17,7 +17,22 @@ impl Ticket {
// as well as some `String` methods. Use the documentation of Rust's standard library
// to find the most appropriate options -> https://doc.rust-lang.org/std/string/struct.String.html
fn new(title: String, description: String, status: String) -> Self {
todo!();
if status != "To-Do" && status != "In Progress" && status != "Done" {
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed")
}
if title.is_empty() {
panic!("Title cannot be empty")
}
if description.is_empty() {
panic!("Description cannot be empty")
}
if title.len() > 50 {
panic!("Title cannot be longer than 50 bytes")
}
if description.len() > 500 {
panic!("Description cannot be longer than 500 bytes")
}
Self {
title,
description,

View File

@@ -1,6 +1,7 @@
mod helpers {
// TODO: Make this code compile, either by adding a `use` statement or by using
// the appropriate path to refer to the `Ticket` struct.
use super::Ticket;
fn create_todo_ticket(title: String, description: String) -> Ticket {
Ticket::new(title, description, "To-Do".into())

View File

@@ -1,12 +1,12 @@
mod ticket {
struct Ticket {
pub struct Ticket {
title: String,
description: String,
status: String,
}
impl Ticket {
fn new(title: String, description: String, status: String) -> Ticket {
pub fn new(title: String, description: String, status: String) -> Ticket {
if title.is_empty() {
panic!("Title cannot be empty");
}
@@ -55,7 +55,7 @@ mod tests {
//
// TODO: Once you have verified that the below does not compile,
// comment the line out to move on to the next exercise!
assert_eq!(ticket.description, "A description");
// assert_eq!(ticket.description, "A description");
}
fn encapsulation_cannot_be_violated() {
@@ -68,10 +68,10 @@ mod tests {
//
// TODO: Once you have verified that the below does not compile,
// comment the lines out to move on to the next exercise!
let ticket = Ticket {
title: "A title".into(),
description: "A description".into(),
status: "To-Do".into(),
};
// let ticket = Ticket {
// title: "A title".into(),
// description: "A description".into(),
// status: "To-Do".into(),
// };
}
}

View File

@@ -34,6 +34,17 @@ pub mod ticket {
// - `title` that returns the `title` field.
// - `description` that returns the `description` field.
// - `status` that returns the `status` field.
pub fn title(self) -> String {
self.title
}
pub fn description(self) -> String {
self.description
}
pub fn status(self) -> String {
self.status
}
}
}

View File

@@ -34,16 +34,16 @@ impl Ticket {
}
}
pub fn title(self) -> String {
self.title
pub fn title(&self) -> &String {
&self.title
}
pub fn description(self) -> String {
self.description
pub fn description(&self) -> &String {
&self.description
}
pub fn status(self) -> String {
self.status
pub fn status(&self) -> &String {
&self.status
}
}

View File

@@ -11,21 +11,9 @@ pub struct Ticket {
impl Ticket {
pub fn new(title: String, description: String, status: String) -> Ticket {
if title.is_empty() {
panic!("Title cannot be empty");
}
if title.len() > 50 {
panic!("Title cannot be longer than 50 bytes");
}
if description.is_empty() {
panic!("Description cannot be empty");
}
if description.len() > 500 {
panic!("Description cannot be longer than 500 bytes");
}
if status != "To-Do" && status != "In Progress" && status != "Done" {
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
}
validate_title(&title);
validate_description(&description);
validate_status(&status);
Ticket {
title,
@@ -45,6 +33,45 @@ impl Ticket {
pub fn status(&self) -> &String {
&self.status
}
pub fn set_title(&mut self, title: String) {
validate_title(&title);
self.title = title;
}
pub fn set_description(&mut self, description: String) {
validate_description(&description);
self.description = description;
}
pub fn set_status(&mut self, status: String) {
validate_status(&status);
self.status = status;
}
}
fn validate_title(title: &String) {
if title.is_empty() {
panic!("Title cannot be empty");
}
if title.len() > 50 {
panic!("Title cannot be longer than 50 bytes");
}
}
fn validate_description(description: &String) {
if description.is_empty() {
panic!("Description cannot be empty");
}
if description.len() > 500 {
panic!("Description cannot be longer than 500 bytes");
}
}
fn validate_status(status: &String) {
if status != "To-Do" && status != "In Progress" && status != "Done" {
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
}
}
#[cfg(test)]

View File

@@ -6,16 +6,16 @@ mod tests {
#[test]
fn u16_size() {
assert_eq!(size_of::<u16>(), todo!());
assert_eq!(size_of::<u16>(), 2);
}
#[test]
fn i32_size() {
assert_eq!(size_of::<i32>(), todo!());
assert_eq!(size_of::<i32>(), 4);
}
#[test]
fn bool_size() {
assert_eq!(size_of::<bool>(), todo!());
assert_eq!(size_of::<bool>(), 1);
}
}

View File

@@ -13,7 +13,7 @@ mod tests {
#[test]
fn string_size() {
assert_eq!(size_of::<String>(), todo!());
assert_eq!(size_of::<String>(), 24);
}
#[test]
@@ -23,6 +23,6 @@ mod tests {
// but, in general, the memory layout of structs is a more complex topic.
// If you're curious, check out the "Data layout" section of the Rustonomicon
// https://doc.rust-lang.org/nomicon/data.html for more information.
assert_eq!(size_of::<Ticket>(), todo!());
assert_eq!(size_of::<Ticket>(), 72);
}
}

View File

@@ -13,16 +13,16 @@ mod tests {
#[test]
fn u16_ref_size() {
assert_eq!(size_of::<&u16>(), todo!());
assert_eq!(size_of::<&u16>(), 8);
}
#[test]
fn u64_mut_ref_size() {
assert_eq!(size_of::<&mut u64>(), todo!());
assert_eq!(size_of::<&mut u64>(), 8);
}
#[test]
fn ticket_ref_size() {
assert_eq!(size_of::<&Ticket>(), todo!());
assert_eq!(size_of::<&Ticket>(), 8);
}
}

View File

@@ -2,7 +2,7 @@
// We'll pick the concept up again in a later chapter after covering traits and
// interior mutability.
fn outro() -> &'static str {
"I have a basic understanding of __!"
"I have a basic understanding of destructors!"
}
#[cfg(test)]

View File

@@ -11,3 +11,74 @@
// Integration here has a very specific meaning: they test **the public API** of your project.
// You'll need to pay attention to the visibility of your types and methods; integration
// tests can't access private or `pub(crate)` items.
pub struct Order {
product_name: String,
quantity: u32,
unit_price: u32,
}
impl Order {
pub fn new(product_name: String, quantity: u32, unit_price: u32) -> Order {
validate_product_name(&product_name);
validate_quantity(&quantity);
validate_unit_price(&unit_price);
Order {
product_name,
quantity,
unit_price,
}
}
pub fn product_name(&self) -> &String {
&self.product_name
}
pub fn quantity(&self) -> &u32 {
&self.quantity
}
pub fn unit_price(&self) -> &u32 {
&self.unit_price
}
pub fn set_product_name(&mut self, product_name: String) {
validate_product_name(&product_name);
self.product_name = product_name;
}
pub fn set_quantity(&mut self, quantity: u32) {
validate_quantity(&quantity);
self.quantity = quantity;
}
pub fn set_unit_price(&mut self, unit_price: u32) {
validate_unit_price(&unit_price);
self.unit_price = unit_price;
}
pub fn total(&self) -> u32 {
self.quantity * self.unit_price
}
}
fn validate_product_name(product_name: &String) {
if product_name.is_empty() {
panic!("Product name cannot be empty");
}
if product_name.len() > 300 {
panic!("Product name cannot be longer than 300 bytes");
}
}
fn validate_quantity(quantity: &u32) {
if quantity == &0 {
panic!("Quantity must be greater than zero");
}
}
fn validate_unit_price(unit_price: &u32) {
if unit_price == &0 {
panic!("Unit price must be greater than zero");
}
}

View File

@@ -1,6 +1,6 @@
fn intro() -> &'static str {
// TODO: fix me 👇
"I'm ready to __!"
"I'm ready to learn about traits!"
}
#[cfg(test)]

View File

@@ -3,6 +3,22 @@
//
// Then implement the trait for `u32` and `i32`.
pub trait IsEven {
fn is_even(self) -> bool;
}
impl IsEven for u32 {
fn is_even(self) -> bool {
self % 2 == 0
}
}
impl IsEven for i32 {
fn is_even(self) -> bool {
self % 2 == 0
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -3,9 +3,3 @@
// a foreign type (`u32`, from `std`).
// Look at the compiler error to get familiar with what it looks like.
// Then delete the code below and move on to the next exercise.
impl PartialEq for u32 {
fn eq(&self, _other: &Self) -> bool {
todo!()
}
}

View File

@@ -8,7 +8,13 @@ struct Ticket {
// TODO: Implement the `PartialEq` trait for `Ticket`.
impl PartialEq for Ticket {}
impl PartialEq for Ticket {
fn eq(&self, other: &Self) -> bool {
self.title == other.title
&& self.description == other.description
&& self.status == other.status
}
}
#[cfg(test)]
mod tests {

View File

@@ -8,7 +8,7 @@
// print both sides of the comparison to the terminal.
// If the compared type doesn't implement `Debug`, it doesn't know how to represent them!
#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
struct Ticket {
title: String,
description: String,

View File

@@ -6,7 +6,10 @@
// collections (e.g. BTreeMap).
/// Return the minimum of two values.
pub fn min<T>(left: T, right: T) -> T {
pub fn min<T>(left: T, right: T) -> T
where
T: Ord,
{
if left <= right {
left
} else {

View File

@@ -8,7 +8,7 @@
// You _could_ pass this test by just returning `v.iter().sum()`,
// but that would defeat the purpose of the exercise.
//
// Hint: you won't be able to get the spawn threads to _borrow_
// Hint: you won't be able to get the spawned threads to _borrow_
// slices of the vector directly. You'll need to allocate new
// vectors for each half of the original vector. We'll see why
// this is necessary in the next exercise.

View File

@@ -1,3 +1,5 @@
// TODO: Set `move_forward` to `true` in `ready` when you think you're done with this exercise.
// Feel free to call an instructor to verify your solution!
use channels::data::TicketDraft;
use channels::{launch, Command};
use std::time::Duration;
@@ -24,8 +26,6 @@ fn ready() {
// since our server doesn't expose any **read** actions.
// We have no way to know if the inserts are actually happening and if they
// are happening correctly.
// Set `move_forward` to `true` when you think you're done with this exercise.
// Feel free to call an instructor to verify your solution!
let move_forward = false;
assert!(move_forward);