Compare commits

...

8 commits

Author SHA1 Message Date
mo8it c793416495 Fix typo 2024-07-08 16:50:35 +02:00
mo8it 01343f187b Explain what a factorial is and link to wikipedia for more details 2024-07-08 16:29:43 +02:00
mo8it 69021e1497 Remove stable from book links 2024-07-08 16:00:12 +02:00
mo8it 08c408aae0 Add hint about string concatination with + 2024-07-08 15:20:56 +02:00
mo8it bf698659b0 Sync comment from exercise 2024-07-08 15:20:23 +02:00
mo8it 2d5d70693a errors3: Add a comment to prevent changing the wrong line 2024-07-08 15:05:58 +02:00
mo8it a4091ade5c iterators3: Add IntegerOverflow error variant 2024-07-08 14:40:35 +02:00
mo8it a7a881809f Check is_terminal 2024-07-08 12:53:44 +02:00
11 changed files with 52 additions and 20 deletions

View file

@ -5,5 +5,5 @@ compiler. In this section, we'll go through the most important ones.
## Further information ## Further information
- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html) - [Data Types](https://doc.rust-lang.org/book/ch03-02-data-types.html)
- [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html) - [The Slice Type](https://doc.rust-lang.org/book/ch04-03-slices.html)

View file

@ -12,6 +12,6 @@ the other useful data structure, hash maps, later.
## Further information ## Further information
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html) - [Storing Lists of Values with Vectors](https://doc.rust-lang.org/book/ch08-01-vectors.html)
- [`iter_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.iter_mut) - [`iter_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.iter_mut)
- [`map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) - [`map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map)

View file

@ -14,7 +14,7 @@ Option types are very common in Rust code, as they have a number of uses:
## Further Information ## Further Information
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions) - [Option Enum Format](https://doc.rust-lang.org/book/ch10-01-syntax.html#in-enum-definitions)
- [Option Module Documentation](https://doc.rust-lang.org/std/option/) - [Option Module Documentation](https://doc.rust-lang.org/std/option/)
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html) - [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
- [if let](https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html) - [if let](https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html)

View file

@ -19,6 +19,7 @@ fn main() {
let mut tokens = 100; let mut tokens = 100;
let pretend_user_input = "8"; let pretend_user_input = "8";
// Don't change this line.
let cost = total_cost(pretend_user_input)?; let cost = total_cost(pretend_user_input)?;
if cost > tokens { if cost > tokens {

View file

@ -7,5 +7,5 @@ The simplest and most common use of generics is for type parameters.
## Further information ## Further information
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html) - [Generic Data Types](https://doc.rust-lang.org/book/ch10-01-syntax.html)
- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html) - [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html)

View file

@ -1,12 +1,16 @@
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
enum DivisionError { enum DivisionError {
// Example: 42 / 0
DivideByZero, DivideByZero,
// Only case for `i64`: `i64::MIN / -1` because the result is `i64::MAX + 1`
IntegerOverflow,
// Example: 5 / 2 = 2.5
NotDivisible, NotDivisible,
} }
// TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`. // TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
// Otherwise, return a suitable error. // Otherwise, return a suitable error.
fn divide(a: i32, b: i32) -> Result<i32, DivisionError> { fn divide(a: i64, b: i64) -> Result<i64, DivisionError> {
todo!(); todo!();
} }
@ -42,6 +46,11 @@ mod tests {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero)); assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
} }
#[test]
fn test_integer_overflow() {
assert_eq!(divide(i64::MIN, -1), Err(DivisionError::IntegerOverflow));
}
#[test] #[test]
fn test_not_divisible() { fn test_not_divisible() {
assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible)); assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));

View file

@ -1,5 +1,8 @@
fn factorial(num: u64) -> u64 { fn factorial(num: u64) -> u64 {
// TODO: Complete this function to return the factorial of `num`. // TODO: Complete this function to return the factorial of `num` which is
// defined as `1 * 2 * 3 * … * num`.
// https://en.wikipedia.org/wiki/Factorial
//
// Do not use: // Do not use:
// - early returns (using the `return` keyword explicitly) // - early returns (using the `return` keyword explicitly)
// Try not to use: // Try not to use:

View file

@ -309,7 +309,7 @@ In Rust, there are two ways to define a Vector.
inside the square brackets. This way is simpler when you exactly know inside the square brackets. This way is simpler when you exactly know
the initial values. the initial values.
Check this chapter: https://doc.rust-lang.org/stable/book/ch08-01-vectors.html Check this chapter: https://doc.rust-lang.org/book/ch08-01-vectors.html
of the Rust book to learn more.""" of the Rust book to learn more."""
[[exercises]] [[exercises]]
@ -378,7 +378,7 @@ dir = "06_move_semantics"
test = false test = false
hint = """ hint = """
To find the answer, you can consult the book section "References and Borrowing": To find the answer, you can consult the book section "References and Borrowing":
https://doc.rust-lang.org/stable/book/ch04-02-references-and-borrowing.html https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
The first problem is that `get_char` is taking ownership of the string. So The first problem is that `get_char` is taking ownership of the string. So
`data` is moved and can't be used for `string_uppercase`. `data` is moved to `data` is moved and can't be used for `string_uppercase`. `data` is moved to
@ -416,7 +416,7 @@ to its fields.
There are however some shortcuts that can be taken when instantiating structs. There are however some shortcuts that can be taken when instantiating structs.
Have a look in The Book to find out more: Have a look in The Book to find out more:
https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax""" https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax"""
[[exercises]] [[exercises]]
name = "structs3" name = "structs3"
@ -487,7 +487,7 @@ to add one character to the `if` statement, though, that will coerce the
Side note: If you're interested in learning about how this kind of reference 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 conversion works, you can jump ahead in the book and read this part in the
smart pointers chapter: smart pointers chapter:
https://doc.rust-lang.org/stable/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods""" https://doc.rust-lang.org/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods"""
[[exercises]] [[exercises]]
name = "strings3" name = "strings3"
@ -561,7 +561,7 @@ hint = """
Use the `entry()` and `or_insert()` methods of `HashMap` to achieve this. Use the `entry()` and `or_insert()` methods of `HashMap` to achieve this.
Learn more in The Book: Learn more in The Book:
https://doc.rust-lang.org/stable/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value""" https://doc.rust-lang.org/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value"""
[[exercises]] [[exercises]]
name = "hashmaps3" name = "hashmaps3"
@ -572,7 +572,7 @@ Hint 1: Use the `entry()` and `or_insert()` (or `or_insert_with()`) methods of
exist in the table yet. exist in the table yet.
Learn more in The Book: Learn more in The Book:
https://doc.rust-lang.org/stable/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value https://doc.rust-lang.org/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value
Hint 2: If there is already an entry for a given key, the value returned by Hint 2: If there is already an entry for a given key, the value returned by
`entry()` can be updated based on the existing value. `entry()` can be updated based on the existing value.
@ -585,7 +585,7 @@ https://doc.rust-lang.org/book/ch08-03-hash-maps.html#updating-a-value-based-on-
[[exercises]] [[exercises]]
name = "quiz2" name = "quiz2"
dir = "quizzes" dir = "quizzes"
hint = "No hints this time ;)" hint = "The `+` operator can concatenate a `String` with a `&str`."
# OPTIONS # OPTIONS
@ -739,7 +739,7 @@ name = "generics2"
dir = "14_generics" dir = "14_generics"
hint = """ hint = """
Related section in The Book: Related section in The Book:
https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions""" https://doc.rust-lang.org/book/ch10-01-syntax.html#in-method-definitions"""
# TRAITS # TRAITS
@ -748,7 +748,9 @@ name = "traits1"
dir = "15_traits" dir = "15_traits"
hint = """ hint = """
More about traits in The Book: More about traits in The Book:
https://doc.rust-lang.org/book/ch10-02-traits.html""" https://doc.rust-lang.org/book/ch10-02-traits.html
The `+` operator can concatenate a `String` with a `&str`."""
[[exercises]] [[exercises]]
name = "traits2" name = "traits2"
@ -869,7 +871,7 @@ We expect the method `Rectangle::new` to panic for negative values.
To handle that, you need to add a special attribute to the test function. 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/book/ch11-01-writing-tests.html#checking-for-panics-with-should_panic"""
# STANDARD LIBRARY TYPES # STANDARD LIBRARY TYPES
@ -1005,7 +1007,7 @@ thread-local copy of the numbers.
This is a simple exercise if you understand the underlying concepts, but if this This is a simple exercise if you understand the underlying concepts, but if this
is too much of a struggle, consider reading through all of Chapter 16 in The is too much of a struggle, consider reading through all of Chapter 16 in The
Book: Book:
https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html""" https://doc.rust-lang.org/book/ch16-00-concurrency.html"""
[[exercises]] [[exercises]]
name = "cow1" name = "cow1"

View file

@ -1,6 +1,10 @@
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
enum DivisionError { enum DivisionError {
// Example: 42 / 0
DivideByZero, DivideByZero,
// Only case for `i64`: `i64::MIN / -1` because the result is `i64::MAX + 1`
IntegerOverflow,
// Example: 5 / 2 = 2.5
NotDivisible, NotDivisible,
} }
@ -9,6 +13,10 @@ fn divide(a: i64, b: i64) -> Result<i64, DivisionError> {
return Err(DivisionError::DivideByZero); return Err(DivisionError::DivideByZero);
} }
if a == i64::MIN && b == -1 {
return Err(DivisionError::IntegerOverflow);
}
if a % b != 0 { if a % b != 0 {
return Err(DivisionError::NotDivisible); return Err(DivisionError::NotDivisible);
} }
@ -51,6 +59,11 @@ mod tests {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero)); assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
} }
#[test]
fn test_integer_overflow() {
assert_eq!(divide(i64::MIN, -1), Err(DivisionError::IntegerOverflow));
}
#[test] #[test]
fn test_not_divisible() { fn test_not_divisible() {
assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible)); assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));

View file

@ -6,7 +6,7 @@
// - Append "bar" to the string a specified amount of times // - Append "bar" to the string a specified amount of times
// //
// The exact form of this will be: // The exact form of this will be:
// - The input is going to be a vector of a 2-length tuple, // - The input is going to be a vector of 2-length tuples,
// the first element is the string, the second one is the command. // the first element is the string, the second one is the command.
// - The output element is going to be a vector of strings. // - The output element is going to be a vector of strings.

View file

@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
use app_state::StateFileStatus; use app_state::StateFileStatus;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use std::{ use std::{
io::{self, BufRead, StdoutLock, Write}, io::{self, BufRead, IsTerminal, StdoutLock, Write},
path::Path, path::Path,
process::exit, process::exit,
}; };
@ -148,6 +148,10 @@ fn main() -> Result<()> {
match args.command { match args.command {
None => { None => {
if !io::stdout().is_terminal() {
bail!("Unsupported or missing terminal/TTY");
}
let notify_exercise_names = if args.manual_run { let notify_exercise_names = if args.manual_run {
None None
} else { } else {