diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c41cc9e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..d4f4ba07 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,27 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Rust-Bootcamp-2023" +version = "0.1.0" + +[[package]] +name = "basic-of-rust" +version = "0.1.0" + +[[package]] +name = "complex-type" +version = "0.1.0" + +[[package]] +name = "generic-type" +version = "0.1.0" + +[[package]] +name = "ownership-borrowing" +version = "0.1.0" + +[[package]] +name = "traits" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..a6b5590a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "Rust-Bootcamp-2023" +version = "0.1.0" +edition = "2021" +authors = ["CocDap"] +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[workspace] +members = [ + "./exercises/basic-of-rust", + "./exercises/ownership-borrowing", + "./exercises/complex-type", + "./exercises/generic-type", + "./exercises/traits", + +] + +[[test]] +name = "conditions" +path = "./exercises/basic-of-rust/src/conditions.rs" + +[[test]] +name = "strings" +path = "./exercises/basic-of-rust/src/strings.rs" + +[[test]] +name = "functions" +path = "./exercises/basic-of-rust/src/functions.rs" + +[[test]] +name = "structs" +path = "./exercises/complex-type/src/structs.rs" + +[[test]] +name = "enums" +path = "./exercises/complex-type/src/enums.rs" + +[[test]] +name = "generic-type" +path = "./exercises/generic-type/src/lib.rs" + +[[test]] +name = "traits" +path = "./exercises/traits/src/lib.rs" + + +[dependencies] \ No newline at end of file diff --git a/exercises/basic-of-rust/Cargo.toml b/exercises/basic-of-rust/Cargo.toml new file mode 100644 index 00000000..e954d0a0 --- /dev/null +++ b/exercises/basic-of-rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "basic-of-rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/exercises/basic-of-rust/README.md b/exercises/basic-of-rust/README.md new file mode 100644 index 00000000..34655b98 --- /dev/null +++ b/exercises/basic-of-rust/README.md @@ -0,0 +1,23 @@ +## Complete Basic of Rust exercises +### Conditions ++ Complete `Conditions` (If Else) Exercises in `exercises/basic-of-rust/src/conditions.rs` ++ Run tests to check your implementation + +``` + cargo test --test conditions +``` + +### String ++ Complete `String` Exercises in `exercises/basic-of-rust/src/strings.rs` ++ Run tests to check your implementation +``` + cargo test --test strings +``` + +### Functions ++ Complete `Functions` (fn) Exercises in `exercises/basic-of-rust/src/functions.rs` ++ Run tests to check your implementation + +``` + cargo test --test functions +``` \ No newline at end of file diff --git a/exercises/basic-of-rust/src/conditions.rs b/exercises/basic-of-rust/src/conditions.rs new file mode 100644 index 00000000..4d92e3b3 --- /dev/null +++ b/exercises/basic-of-rust/src/conditions.rs @@ -0,0 +1,148 @@ +//Exercise 1 +// Complete this function to return the bigger number! +// Do not use: +// - another function call +// - additional variables +pub fn bigger(a: i32, b: i32) -> i32 { + todo!() +} + +//Exercise 2 +// Input: Provide an arbitrary value of number +// Check number is Positive or Negative or Zero +// Output: &str +fn check_number(number: u32) -> &'static str { + todo!() +} + +// Exercise 3 +// Step 1: Make me compile! +// Step 2: Get the bar_for_fuzz and default_to_baz tests passing! + +pub fn foo_if_fizz(fizzish: &str) -> &str { + if fizzish == "fizz" { + "foo" + } else { + 1 + } +} + +// Exercise 4 +// Determine if a given year is a leap year +// Implement logic +fn is_leap_year(year: i32) -> bool { + todo!() +} + +// Exercise 5 +// Calculate the factorial of a number +// Implement logic +fn factorial(n: u32) -> u32 { + todo!() +} + +// Exercise 6 +// Check if a number is prime +// Implement logic + +fn is_prime(n: u32) -> bool { + todo!() +} + + +// Don't mind this for now :) +#[cfg(test)] +mod tests { + use super::*; + + // Test for exercise 1 + #[test] + fn ten_is_bigger_than_eight() { + assert_eq!(10, bigger(10, 8)); + } + // Test for exercise 1 + #[test] + fn fortytwo_is_bigger_than_thirtytwo() { + assert_eq!(42, bigger(32, 42)); + } + // Test for exercise 2 + #[test] + fn test_check_number_positive() { + let result = check_number(10); + assert_eq!(result, "Positive"); + } + // Test for exercise 2 + #[test] + fn test_check_number_negative() { + let result = check_number(-5); + assert_eq!(result, "Negative"); + } + // Test for exercise 2 + #[test] + fn test_check_number_zero() { + let result = check_number(0); + assert_eq!(result, "Zero"); + } + + // Test for exercise 3 + #[test] + fn foo_for_fizz() { + assert_eq!(foo_if_fizz("fizz"), "foo") + } + + // Test for exercise 3 + #[test] + fn bar_for_fuzz() { + assert_eq!(foo_if_fizz("fuzz"), "bar") + } + + // Test for exercise 3 + #[test] + fn default_to_baz() { + assert_eq!(foo_if_fizz("literally anything"), "baz") + } + + // Test for exercise 4 + #[test] + fn test_leap_year() { + assert_eq!(is_leap_year(2020), true); + assert_eq!(is_leap_year(2000), true); + assert_eq!(is_leap_year(1600), true); + } + + // Test for exercise 4 + #[test] + fn test_non_leap_year() { + assert_eq!(is_leap_year(2021), false); + assert_eq!(is_leap_year(1900), false); + assert_eq!(is_leap_year(1800), false); + } + + // Test for exercise 5 + #[test] + fn test_factorial() { + assert_eq!(factorial(0), 1); + assert_eq!(factorial(1), 1); + assert_eq!(factorial(5), 120); + assert_eq!(factorial(10), 3628800); + } + + // Test for exercise 6 + #[test] + fn test_prime_number() { + assert_eq!(is_prime(2), true); + assert_eq!(is_prime(7), true); + assert_eq!(is_prime(13), true); + assert_eq!(is_prime(19), true); + } + // Test for exercise 6 + #[test] + fn test_non_prime_number() { + assert_eq!(is_prime(1), false); + assert_eq!(is_prime(4), false); + assert_eq!(is_prime(10), false); + assert_eq!(is_prime(15), false); + } + + +} \ No newline at end of file diff --git a/exercises/basic-of-rust/src/functions.rs b/exercises/basic-of-rust/src/functions.rs new file mode 100644 index 00000000..c2b37e31 --- /dev/null +++ b/exercises/basic-of-rust/src/functions.rs @@ -0,0 +1,97 @@ +// Exercise 1 +// Fix all errors +fn sum(x, y: i32) { + x + y; +} + +//Exercise 2 +// Input: Provide an arbitrary value of n +// Implement sum function: 1+2+3+..n +// Output: Calculate sum 1 to n +pub fn sum_one_to_n(n: u32) -> u32 { + // your code for summing all digits from 1 to `n` (inclusive) should go + // here (you can remove the sample return of `0`) + 0 +} + +// Exercise 3 +// Input: list of arbitrary numbers +// Problem: Calculate the average of a list of numbers +// Output: Average Number +fn calculate_average(numbers: &[f64]) -> f64 { + todo!() +} + +// Exercise 4 +// Calculate the sum of all even numbers in a list +fn sum_even_numbers(numbers: &[i32]) -> i32 { + todo!() +} + + +#[cfg(test)] +mod tests { + use super::*; + + // Test for exercise 1 + #[test] + fn sum_should_work() { + let (x, y) = (1, 2); + let s = sum(x, y); + + assert_eq!(s, 3); + } + + // Test for exercise 2 + #[test] + fn test_sum_0() { + let result = sum_one_to_n(0); + + assert_eq!(result, 0); + } + + // Test for exercise 2 + #[test] + fn test_sum_1() { + let result = sum_one_to_n(1); + + assert_eq!(result, 1); + } + + // Test for exercise 2 + #[test] + fn test_sum_100() { + let result = sum_one_to_n(100); + + assert_eq!(result, 5050); + } + + // Test for exercise 3 + #[test] + fn test_calculate_average() { + // Test case 1: Non-empty slice + let numbers = [2.5, 4.8, 6.3, 1.7, 3.9]; + let result = calculate_average(&numbers); + assert_eq!(result, 3.84); + + } + + // Test for exercise 3 + #[test] + fn test_calculate_average_empty() { + // Test case 1: Non-empty slice + let numbers = []; + let result = calculate_average(&numbers); + assert_eq!(result, 0.0); + + } + + // Test for exercise 4 + #[test] + fn test_sum_even_numbers() { + assert_eq!(sum_even_numbers(&[1, 2, 3, 4, 5, 6]), 12); + assert_eq!(sum_even_numbers(&[10, 20, 30, 40, 50]), 150); + assert_eq!(sum_even_numbers(&[15, 25, 35, 45, 55]), 0); + assert_eq!(sum_even_numbers(&[-2, 0, 2, 4, 6]), 10); + } +} diff --git a/exercises/basic-of-rust/src/lib.rs b/exercises/basic-of-rust/src/lib.rs new file mode 100644 index 00000000..65ca46d1 --- /dev/null +++ b/exercises/basic-of-rust/src/lib.rs @@ -0,0 +1,4 @@ +mod conditions; +mod strings; +mod functions; + diff --git a/exercises/basic-of-rust/src/strings.rs b/exercises/basic-of-rust/src/strings.rs new file mode 100644 index 00000000..998427d9 --- /dev/null +++ b/exercises/basic-of-rust/src/strings.rs @@ -0,0 +1,99 @@ +// Exercise 1 +#[allow(dead_code)] +fn exercise1(color: &str) -> String { + todo!() +} + +// Exercise 2 +// Fix all errors without adding newline +fn exercise2() -> String { + let s = String::from("hello"); + s.push(','); + s.push(" world"); + s += "!".to_string(); + s +} +// Exercise 3 +// Fix errors without removing any line +fn exercise3() -> String { + let s1 = String::from("hello,"); + let s2 = String::from("world!"); + let s3 = s1 + s2; + s3 +} + +// Exercise 4 +// Reverse a string + +fn reverse_string(input: &str) -> String { + todo!() +} + + +// Exercise 5 +// Check if a string is a palindrome +fn is_palindrome(word: &str) -> bool { + todo!() +} + +// Exercise 6 +// Count the occurrences of a character in a string +fn count_char_occurrences(string: &str, ch: char) -> usize { + todo!() +} + +#[cfg(test)] +mod tests { + use super::*; + + // Test for exercise 1 + #[test] + fn exercise1_work() { + assert_eq!("white".to_string(), exercise1("white")); + } + + // Test for exercise 2 + #[test] + fn exercise2_work() { + assert_eq!("hello, world!".to_string(), exercise2()); + } + + // Test for exercise 3 + #[test] + fn exercise3_work() { + assert_eq!("hello, world!".to_string(), exercise3()); + } + + // Test for exercise 4 + #[test] + fn test_reverse_string() { + assert_eq!(reverse_string("hello"), "olleh"); + assert_eq!(reverse_string("rust"), "tsur"); + assert_eq!(reverse_string("world"), "dlrow"); + assert_eq!(reverse_string(""), ""); + } + + // Test for exercise 5 + #[test] + fn test_palindrome() { + assert_eq!(is_palindrome("level"), true); + assert_eq!(is_palindrome("deed"), true); + assert_eq!(is_palindrome("Rotor"), true); + } + // Test for exercise 5 + #[test] + fn test_non_palindrome() { + assert_eq!(is_palindrome("hello"), false); + assert_eq!(is_palindrome("world"), false); + } + + // Test for exercise 6 + + #[test] + fn test_count_char_occurrences() { + assert_eq!(count_char_occurrences("Hello", 'l'), 2); + assert_eq!(count_char_occurrences("Rust is fun", 'u'), 1); + assert_eq!(count_char_occurrences("Mississippi", 's'), 4); + } + +} \ No newline at end of file diff --git a/exercises/complex-type/Cargo.toml b/exercises/complex-type/Cargo.toml new file mode 100644 index 00000000..86b97fec --- /dev/null +++ b/exercises/complex-type/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "complex-type" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/exercises/complex-type/README.md b/exercises/complex-type/README.md new file mode 100644 index 00000000..bf728d55 --- /dev/null +++ b/exercises/complex-type/README.md @@ -0,0 +1,15 @@ +## Complete Complex Type exercises +### Enums ++ Make it compile and Complete `Enums` Exercises in `exercises/complex-type/src/enums.rs` ++ Run tests to check your implementation + +``` + cargo test --test enums +``` + +### Structs ++ Make it compile and Complete `Struct` Exercises in `exercises/complex-type/src/structs.rs` ++ Run tests to check your implementation +``` + cargo test --test structs +``` \ No newline at end of file diff --git a/exercises/complex-type/src/enums.rs b/exercises/complex-type/src/enums.rs new file mode 100644 index 00000000..d80b8585 --- /dev/null +++ b/exercises/complex-type/src/enums.rs @@ -0,0 +1,159 @@ +// Exercise 1 +// Fill in the blank and fix the errors +// Make it compile +enum MessageOne { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} +fn show_message(msg: MessageOne) { + println!("{}", msg); +} + +fn exercise1() { + let msgs: __ = [ + MessageOne::Quit, + MessageOne::Move { x: 1, y: 3 }, + MessageOne::ChangeColor(255, 255, 0), + ]; + + for msg in msgs { + show_message(msg) + } +} + +// Exercise 2 +// Fill in the blank and fix the errors +// Make it compile +// Run tests +enum Message { + // TODO: implement the message variant types based on their usage below +} + +struct Point { + x: u8, + y: u8, +} + +struct State { + color: (u8, u8, u8), + position: Point, + quit: bool, +} + +impl State { + fn change_color(&mut self, color: (u8, u8, u8)) { + self.color = color; + } + + fn quit(&mut self) { + self.quit = true; + } + + fn echo(&self, s: String) { + println!("{}", s); + } + + fn move_position(&mut self, p: Point) { + self.position = p; + } + + fn process(&mut self, message: Message) { + // TODO: create a match expression to process the different message variants + // Remember: When passing a tuple as a function argument, you'll need extra parentheses: fn function((t, u, p, l, e)) + } +} + + +// Exercise 3 +// Fix the errors +// Run tests +enum Direction { + North, + East, + South, + West, +} + +impl Direction { + fn opposite(&self) -> Direction { + match self { + //TODO + } + } +} + + +// Exercise 4 +// Implement logic : +// Run tests +// Enum representing arithmetic operations +enum Operation { + Add, + Subtract, + Multiply, + Divide, +} + +// Perform arithmetic operations +fn perform_operation(operation: Operation, num1: f64, num2: f64) -> f64 { + match operation { + // TODO + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + // Test for exercise 2 + + #[test] + fn exercise2_should_work() { + let mut state = State { + quit: false, + position: Point { x: 0, y: 0 }, + color: (0, 0, 0), + }; + state.process(Message::ChangeColor(255, 0, 255)); + state.process(Message::Echo(String::from("hello world"))); + state.process(Message::Move(Point { x: 10, y: 15 })); + state.process(Message::Quit); + + assert_eq!(state.color, (255, 0, 255)); + assert_eq!(state.position.x, 10); + assert_eq!(state.position.y, 15); + assert_eq!(state.quit, true); + } + + // Test for exercise 3 + + #[test] + fn exercise3_should_work() { + assert_eq!(Direction::North.opposite(), Direction::South); + assert_eq!(Direction::East.opposite(), Direction::West); + assert_eq!(Direction::South.opposite(), Direction::North); + assert_eq!(Direction::West.opposite(), Direction::East); + } + + // Test for exercise 4 + #[test] + fn test_perform_operation() { + let add_result = perform_operation(Operation::Add, 5.0, 3.0); + assert_eq!(add_result, 8.0); + + let subtract_result = perform_operation(Operation::Subtract, 10.0, 4.0); + assert_eq!(subtract_result, 6.0); + + let multiply_result = perform_operation(Operation::Multiply, 2.5, 4.0); + assert_eq!(multiply_result, 10.0); + + let divide_result = perform_operation(Operation::Divide, 12.0, 3.0); + assert_eq!(divide_result, 4.0); + + } + +} + diff --git a/exercises/complex-type/src/lib.rs b/exercises/complex-type/src/lib.rs new file mode 100644 index 00000000..dc7f4341 --- /dev/null +++ b/exercises/complex-type/src/lib.rs @@ -0,0 +1,2 @@ +mod structs; +mod enums; diff --git a/exercises/complex-type/src/structs.rs b/exercises/complex-type/src/structs.rs new file mode 100644 index 00000000..d4ce0508 --- /dev/null +++ b/exercises/complex-type/src/structs.rs @@ -0,0 +1,257 @@ +// Exercise 1 +// Fix the error +// Make it compile +// Run test +struct Person { + name: String, + age: u8, + hobby: String +} +fn exercise1() -> Person { + let age = 30; + // Hobby = Rust + let p = Person { + name: String::from("sunface"), + age, + hobby: String::from("Rust") + }; + + p +} + +// Exercise 2 +// Fix the error +// Make it compile +// Run test + +// Define the struct +struct Agent { + name: String, + age: u32, +} + +// Implementation of methods for the Person struct +impl Agent { + // Create a new Person instance + fn new(name: String, age: u32) -> Agent { + Agent { name, age } + } + + // Get the name of the person + fn get_name(&self) -> &str { + todo!() + } + + // Get the age of the person + fn get_age(&self) -> u32 { + todo!() + } +} + +// Exercise 3 +// Fix the error +// Make it compile +// Run test +struct Calculator { + value: i32, +} + +impl Calculator { + fn new() -> Self { + Calculator { value: 0 } + } + + fn add(&self, num: i32) { + self.value += num; + } + + fn subtract(mut self, num: i32) { + self.value -= num; + } + fn clear(self) { + self.value = 0; + } + + fn get_value(self) -> i32 { + self.value + } +} + +// Exercise 4 +// Make it compile +#[derive(Debug)] +struct User { + first: String, + last: String, + age: u32, +} + +fn exercise4() { + let u1 = User { + first: String::from("John"), + last: String::from("Doe"), + age: 22, + }; + + let u2 = User { + first: String::from("Mary"), + ..u1 + + }; + + println!("user: {:#?}", u1); + +} + +// Exercise 5 +// Make it compile +struct Foo { + str_val: String, + int_val: i32, +} + +fn exercise5() { + let mut foos = Vec::new(); + foos.push(Foo { + str_val: "ten".to_string(), + int_val: 10, + }); + foos.push(Foo { + str_val: "twenty".to_string(), + int_val: 20, + }); + + + let moved = foos[0]; + + + let moved_field = foos[0].str_val; +} + +// Exercise 6 +// Structs contain data, but can also have logic. In this exercise we have +// defined the Package struct and we want to test some logic attached to it. +// Make the code compile and the tests pass! + +#[derive(Debug)] +struct Package { + sender_country: String, + recipient_country: String, + weight_in_grams: i32, +} + +impl Package { + fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package { + if weight_in_grams <= 0 { + panic!("Can not ship a weightless package.") + } else { + Package { + sender_country, + recipient_country, + weight_in_grams, + } + } + } + + fn is_international(&self) -> ??? { + // Something goes here... + } + + fn get_fees(&self, cents_per_gram: i32) -> ??? { + // Something goes here... + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Test for exercise 1 + #[test] + fn exercise1_should_work() { + let p = exercise1(); + + let p_expectation = Person { + name: String::from("sunface"), + age: 30, + hobby:String::from("Rust") + }; + assert_eq!(p, p_expectation); + + } + + // Test for exercise 2 + #[test] + fn exercise2_should_work() { + // Create a new Person instance + let agent = Agent::new(String::from("John"), 30); + + // Test the get_name method + assert_eq!(agent.get_name(), "John"); + + // Test the get_age method + assert_eq!(agent.get_age(), 30); + } + + // Test for exercise 3 + #[test] + fn exercise3_should_work() { + let mut calculator = Calculator::new(); + calculator.add(5); + assert_eq!(calculator.get_value(), 5); + + calculator.subtract(2); + assert_eq!(calculator.get_value(), 3); + + calculator.clear(); + assert_eq!(calculator.get_value(), 0); + + } + + + // Test for exercise 6 + #[test] + #[should_panic] + fn fail_creating_weightless_package() { + let sender_country = String::from("Spain"); + let recipient_country = String::from("Austria"); + + Package::new(sender_country, recipient_country, -2210); + } + + // Test for exercise 6 + #[test] + fn create_international_package() { + let sender_country = String::from("Spain"); + let recipient_country = String::from("Russia"); + + let package = Package::new(sender_country, recipient_country, 1200); + + assert!(package.is_international()); + } + + // Test for exercise 6 + #[test] + fn create_local_package() { + let sender_country = String::from("Canada"); + let recipient_country = sender_country.clone(); + + let package = Package::new(sender_country, recipient_country, 1200); + + assert!(!package.is_international()); + } + // Test for exercise 6 + #[test] + fn calculate_transport_fees() { + let sender_country = String::from("Spain"); + let recipient_country = String::from("Spain"); + + let cents_per_gram = 3; + + let package = Package::new(sender_country, recipient_country, 1500); + + assert_eq!(package.get_fees(cents_per_gram), 4500); + assert_eq!(package.get_fees(cents_per_gram * 2), 9000); + } + +} \ No newline at end of file diff --git a/exercises/generic-type/Cargo.toml b/exercises/generic-type/Cargo.toml new file mode 100644 index 00000000..8f1e556b --- /dev/null +++ b/exercises/generic-type/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "generic-type" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/exercises/generic-type/README.md b/exercises/generic-type/README.md new file mode 100644 index 00000000..9f9caeee --- /dev/null +++ b/exercises/generic-type/README.md @@ -0,0 +1,4 @@ +## Complete Generic type exercises +### Generic type + ++ Make it compile, add logic code `Generic Type` exercises in `exercises/generic-type/src/lib.rs` diff --git a/exercises/generic-type/src/lib.rs b/exercises/generic-type/src/lib.rs new file mode 100644 index 00000000..da88f9a9 --- /dev/null +++ b/exercises/generic-type/src/lib.rs @@ -0,0 +1,145 @@ +// Exercise 1 +// Implement struct Point to make it work. +// Make it compile +fn exercise1() { + let integer = Position { x: 5, y: 10 }; + let float = Position { x: 1.0, y: 4.0 }; +} + +struct Position { x: T, y: T } + + + +// Exercise 2 +// Modify this struct to make the code work +// Make it compile +struct Point { + x: T, + y: String, +} + +fn exercise2() { + // DON'T modify this code. + let p = Point{x: 5, y : "hello".to_string()}; +} + + + +// Exercise 3 +// Make it compile +// Add generic for Val to make the code work, DON'T modify the code in `main`. +struct Val { + val: T, +} + +impl Val { + fn value(&self) -> &T { + &self.val + } +} + + +fn exercise3() { + let x = Val{ val: 3.0 }; + let y = Val{ val: "hello".to_string()}; + println!("{}, {}", x.value(), y.value()); +} + +// Exercise 4 +// Find the maximum value in a collection +// Make it compile +// Implementing logic +// Run tests + +fn find_max(collection: &[T]) -> Option<&T> { + collection.iter().max() +} + +// Exercise 5 +// Reverse the elements in a collection +// Make it compile +// Run tests +fn reverse_collection(collection: &mut [T]) { + collection.reverse(); +} + +// Exercise 6 +// Function to check if a collection contains a specific value +fn contains_value(collection: &[T], value: &T) -> bool { + collection.contains(value) +} + +// Unit tests +#[cfg(test)] +mod tests { + use super::*; + + // Test for exercise 4 + #[test] + fn test_find_max_with_numbers() { + let numbers = vec![1, 5, 3, 8, 2]; + assert_eq!(find_max(&numbers), Some(&8)); + } + + // Test for exercise 4 + #[test] + fn test_find_max_with_strings() { + let strings = vec!["apple", "banana", "cherry", "durian"]; + assert_eq!(find_max(&strings), Some(&"durian")); + } + + // Test for exercise 4 + #[test] + fn test_find_max_with_empty_collection() { + let empty: Vec = Vec::new(); + assert_eq!(find_max(&empty), None); + } + + // Test for exercise 5 + #[test] + fn test_reverse_collection_with_numbers() { + let mut numbers = vec![1, 2, 3, 4, 5]; + reverse_collection(&mut numbers); + assert_eq!(numbers, vec![5, 4, 3, 2, 1]); + } + + // Test for exercise 5 + #[test] + fn test_reverse_collection_with_strings() { + let mut strings = vec!["apple", "banana", "cherry", "durian"]; + reverse_collection(&mut strings); + assert_eq!(strings, vec!["durian", "cherry", "banana", "apple"]); + } + + // Test for exercise 5 + #[test] + fn test_reverse_collection_with_empty_collection() { + let mut empty: Vec = Vec::new(); + reverse_collection(&mut empty); + assert_eq!(empty, Vec::::new()); + } + + // Test for exercise 6 + #[test] + fn test_contains_value_with_numbers() { + let numbers = vec![1, 2, 3, 4, 5]; + assert_eq!(contains_value(&numbers, &3), true); + assert_eq!(contains_value(&numbers, &6), false); + } + + // Test for exercise 6 + #[test] + fn test_contains_value_with_strings() { + let strings = vec!["apple", "banana", "cherry", "durian"]; + assert_eq!(contains_value(&strings, &"banana"), true); + assert_eq!(contains_value(&strings, &"grape"), false); + } + + // Test for exercise 6 + #[test] + fn test_contains_value_with_empty_collection() { + let empty: Vec = Vec::new(); + assert_eq!(contains_value(&empty, &5), false); + } + +} diff --git a/exercises/ownership-borrowing/Cargo.toml b/exercises/ownership-borrowing/Cargo.toml new file mode 100644 index 00000000..55e140fa --- /dev/null +++ b/exercises/ownership-borrowing/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ownership-borrowing" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/exercises/ownership-borrowing/README.md b/exercises/ownership-borrowing/README.md new file mode 100644 index 00000000..3df30ce7 --- /dev/null +++ b/exercises/ownership-borrowing/README.md @@ -0,0 +1,4 @@ +## Complete Ownership and Borrowing exercises +### Ownership and Borrowing + ++ Make it compile `Ownership and Borrowing` exercises in `exercises/ownership-borrowing/src/lib.rs` diff --git a/exercises/ownership-borrowing/src/lib.rs b/exercises/ownership-borrowing/src/lib.rs new file mode 100644 index 00000000..46ccf53c --- /dev/null +++ b/exercises/ownership-borrowing/src/lib.rs @@ -0,0 +1,131 @@ +// Exercise 1 +// Make it compile +fn exercise1() { + // Use as many approaches as you can to make it work + let x = String::from("hello, world"); + let y = x; + let z = x; +} + +// Exercise 2 +// Make it compile +// Don't modify code in exercise2 function! +fn exercise2() { + let s1 = String::from("hello, world"); + let s2 = take_ownership(s1); + + println!("{}", s2); +} +// Only modify the code below! +fn take_ownership(s: String) { + println!("{}", s); +} + +// Exercise 3 +// Make it compile +// Dont care about logic +fn exercise3() { + let values: Vec = vec![ + 2817.42, 2162.17, 3756.57, 2817.42, -2817.42, 946.9, 2817.42, 964.42, 795.43, 3756.57, + 139.34, 903.58, -3756.57, 939.14, 828.04, 1120.04, 604.03, 3354.74, 2748.06, 1470.8, + 4695.71, 71.11, 2391.48, 331.29, 1214.69, 863.52, 7810.01, + ]; + + let values_number = values.len(); + + let additions: Vec = vec![0]; + + println!("{:?}", values_number); + + while additions.len() > 0 { + let mut addition: f64 = 0.0; + + // Sumar valores en additions + for element_index in additions { + let addition_aux = values[element_index]; + addition = addition_aux + addition; + } + } +} + +// Exercise 4 +// Make it compile +fn exercise4(value: u32) -> &'static str { + let str_value = value.to_string(); // Convert u32 to String + let str_ref: &str = &str_value; // Obtain a reference to the String + str_ref // Return the reference to the String +} + +// Exercise 5 +// Make it compile +use std::collections::HashMap; +fn exercise5() { + let mut my_map = HashMap::from([(1, "1.0".to_string()), (2, "2.0".to_string())]); + + let key = 3; + + let res = match my_map.get(&key) { + Some(child) => child, + None => { + let value = "3.0".to_string(); + my_map.insert(key, value); + &value // HERE IT FAILS + } + }; + + println!("{}", res); +} + +// Exercise 6 +// Make it compile + +use std::io; + +fn exercise6() { + let mut prev_key: &str = ""; + + for line in io::stdin().lines() { + let s = line.unwrap(); + + let data: Vec<&str> = s.split("\t").collect(); + if prev_key.len() == 0 { + prev_key = data[0]; + } + } +} + +// Exercise 7 +// Make it compile +fn exercise7() { + let mut v: Vec<&str> = Vec::new(); + { + let chars = [b'x', b'y', b'z']; + let s: &str = std::str::from_utf8(&chars).unwrap(); + v.push(&s); + } + println!("{:?}", v); +} + +// Exercise 8 +// Make it compile +fn exercise8() { + let mut accounting = vec!["Alice", "Ben"]; + + loop { + let mut add_input = String::from(""); + + io::stdin() + .read_line(&mut add_input) + .expect("Failed to read line"); + + let add_vec: Vec<&str> = add_input.trim()[..].split_whitespace().collect(); + + if add_vec.len() < 1 { + println!("Incorrect input, try again"); + continue; + } + + let person = add_vec[0]; + accounting.push(person); + } +} diff --git a/exercises/traits/Cargo.toml b/exercises/traits/Cargo.toml new file mode 100644 index 00000000..460f45f0 --- /dev/null +++ b/exercises/traits/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "traits" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/exercises/traits/README.md b/exercises/traits/README.md new file mode 100644 index 00000000..f87c4b5c --- /dev/null +++ b/exercises/traits/README.md @@ -0,0 +1,10 @@ +## Complete Trait exercises +### Trait + ++ Make it compile and Complete `Traits` exercises in `exercises/traits/src/lib.rs` + ++ Run tests to check your implementation + +``` + cargo test --test traits +``` \ No newline at end of file diff --git a/exercises/traits/src/lib.rs b/exercises/traits/src/lib.rs new file mode 100644 index 00000000..1096ee35 --- /dev/null +++ b/exercises/traits/src/lib.rs @@ -0,0 +1,210 @@ +// Exercise 1 +// Fill in the two impl blocks to make the code work. +// Make it compile +// Run tests +trait Hello { + fn say_hi(&self) -> String { + String::from("hi") + } + + fn say_something(&self) -> String; +} + +//TODO +struct Student {} +impl Hello for Student { + fn say_something(&self) -> String { + String::from("I'm a good student") + } +} +//TODO +struct Teacher {} +impl Hello for Teacher { + fn say_hi(&self) -> String { + String::from("Hi, I'm your new teacher") + } + fn say_something(&self) -> String { + String::from("I'm not a bad teacher") + } +} + + +// Exercise 2 +// Make it compile in unit test for exercise 2 +// Hint: use #[derive] for struct Point +// Run tests +#[derive(PartialEq, Debug)] +struct Point { + x: i32, + y: i32, +} + + +// Exercise 3 +// Make it compile +// Implement `fn sum` with trait bound in two ways. +// Run tests +// Hint: Trait Bound +fn sum>(x: T, y: T) -> T { + x + y +} + + +// Exercise 4 +// Fix errors and implement +// Hint: Static Dispatch and Dynamic Dispatch +// Run tests +trait Foo { + fn method(&self) -> String; +} + +impl Foo for u8 { + fn method(&self) -> String { format!("u8: {}", *self) } +} + +impl Foo for String { + fn method(&self) -> String { format!("string: {}", *self) } +} + +// IMPLEMENT below with generics and parameters +fn static_dispatch(x: T) { + println!("{}", x.method()); +} + +// Implement below with trait objects and parameters +fn dynamic_dispatch(x: &dyn Foo) { + println!("{}", x.method()); +} + +// Exercise 5 +// Fix errors and fill in the blanks +// Run tests +// Hint: &dyn and Box +trait Draw { + fn draw(&self) -> String; +} + +impl Draw for u8 { + fn draw(&self) -> String { + format!("u8: {}", *self) + } +} + +impl Draw for f64 { + fn draw(&self) -> String { + format!("f64: {}", *self) + } +} + +fn draw_with_box(x: Box) { + x.draw(); +} + +fn draw_with_ref(x: &dyn Draw) { + x.draw(); +} + +// Exercise 6 +// Fix errors and implement +// Run tests +// Hint: Associated Type + +trait Container { + type Item; + fn insert(&mut self, item: Self::Item); + fn remove(&mut self) -> Option; + fn is_empty(&self) -> bool; +} + +struct Stack { + items: Vec, +} + +//TODO implement Container for Stack +impl Container for Stack { + type Item = T; + + fn insert(&mut self, item: Self::Item) { + self.items.push(item); + } + + fn remove(&mut self) -> Option { + self.items.pop() as Option + } + + fn is_empty(&self) -> bool { + self.items.is_empty() + } +} + + + +#[cfg(test)] +mod tests { + use super::*; + + // Test for exercise 2 + + #[test] + fn exercise1_should_work() { + let s = Student {}; + assert_eq!(s.say_hi(), "hi"); + assert_eq!(s.say_something(), "I'm a good student"); + + let t = Teacher {}; + assert_eq!(t.say_hi(), "Hi, I'm your new teacher"); + assert_eq!(t.say_something(), "I'm not a bad teacher"); + } + + #[test] + fn exercise2_should_work() { + let point1 = Point { x: 1, y: 2 }; + let point2 = Point { x: 1, y: 2 }; + let point3 = Point { x: 3, y: 4 }; + + assert_eq!(point1, point2); + assert_ne!(point1, point3); + } + + #[test] + fn exercise3_should_work() { + assert_eq!(sum(1, 2), 3); + } + + #[test] + fn exercise4_should_work() { + let x = 5u8; + let y = "Hello".to_string(); + + static_dispatch(x); + dynamic_dispatch(&y); + } + + #[test] + fn exercise5_should_work() { + let x = 1.1f64; + let y = 8u8; + + // Draw x. + draw_with_box(Box::new(x)); + + // Draw y. + draw_with_ref(&y); + } + + #[test] + fn exercise6_should_work(){ + let mut stack: Stack = Stack { items: Vec::new() }; + assert!(stack.is_empty()); + stack.insert(1); + stack.insert(2); + stack.insert(3); + assert!(!stack.is_empty()); + assert_eq!(stack.remove(), Some(3)); + assert_eq!(stack.remove(), Some(2)); + assert_eq!(stack.remove(), Some(1)); + assert_eq!(stack.remove(), None); + assert!(stack.is_empty()); + } + +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000..4f40d9b2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, Rust Bootcamp by VBI Academy!"); +}