diff --git a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/01.rs b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/01.rs index 76cbeca..49983c8 100644 --- a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/01.rs +++ b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/01.rs @@ -2,11 +2,11 @@ fn main() { println!("{}", multiply(10, 20)); } -fn multiply(a: i32, b: i32) { +fn multiply(a: i32, b: i32) -> i32 { a * b } -// Tests; run with `cargo test --bin 01` +// Tests; run with cargo test --bin 01 #[cfg(test)] mod tests { use super::*; diff --git a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/02.rs b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/02.rs index 8e677a5..519ff7f 100644 --- a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/02.rs +++ b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/02.rs @@ -1,13 +1,13 @@ fn main() { - if (bigger(10, 20)) { + if bigger(10, 20) { println!("10 is bigger than 20"); } else { println!("10 still isn't bigger than 20"); } } -fn bigger(a: i32, b: i32) -> i32 { - // TODO +fn bigger(a: i32, b: i32) -> bool { + a > b } #[cfg(test)] diff --git a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/03.rs b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/03.rs index 365132e..8968424 100644 --- a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/03.rs +++ b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/03.rs @@ -1,7 +1,8 @@ fn main() { let input = [23, 82, 16, 45, 21, 94, 12, 34]; - // TODO + let largest = input.iter().max().unwrap(); + let smallest = input.iter().min().unwrap(); - println!("{} is largest and {} is smallest"); + println!("{} is largest and {} is smallest", largest, smallest); } diff --git a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/04.rs b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/04.rs index 8926e1d..7e15db5 100644 --- a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/04.rs +++ b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/04.rs @@ -1,9 +1,9 @@ fn main() { - for (n in [10, 20, 30, 40]) { + for n in [10, 20, 30, 40] { let mult = if n < 25 { n * 4 } else { - n * 3; + n * 3 }; println!("{}", mult); } diff --git a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/05.rs b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/05.rs index faacb16..072907a 100644 --- a/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/05.rs +++ b/2-foundations-of-rust/1-basic-syntax/1-basic-syntax/src/bin/05.rs @@ -1,10 +1,11 @@ fn main() { - let data = [22, 12, 13, 17, 18]; + let mut data = [22, 12, 13, 17, 18]; for i in 0..5 { - data.i = floored_half(data.i); + data[i] = floored_half(data[i]); } + println!("{:?}", data); } -fn floored_half(data: i32) { +fn floored_half(data: i32) -> i32 { data / 2 } diff --git a/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/02.rs b/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/02.rs index 02211b8..bdf1e0c 100644 --- a/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/02.rs +++ b/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/02.rs @@ -5,11 +5,11 @@ fn main() { let s0 = String::from("Hello"); - let mut s1 = append_to_string(s0); - // Don't change the following line! println!("{} == `{}`", stringify!(s0), s0); + let mut s1 = append_to_string(s0); + s1.push('!'); println!("{} == `{}`", stringify!(s1), s1); @@ -22,3 +22,4 @@ fn append_to_string(s: String) -> String { s } + diff --git a/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/03.rs b/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/03.rs index 8473e69..d120c52 100644 --- a/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/03.rs +++ b/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/03.rs @@ -12,8 +12,9 @@ fn main() { println!("{} == `{}`", stringify!(s1), s1); } -fn append_to_string(s: String) -> String { +fn append_to_string(mut s: String) -> String { s.push_str("Hello World"); s } + diff --git a/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/04.rs b/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/04.rs index 8631c1a..f6ae008 100644 --- a/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/04.rs +++ b/2-foundations-of-rust/2-ownership-and-references/1-move-semantics/src/bin/04.rs @@ -3,9 +3,7 @@ //! function. fn main() { - let s0 = String::new(); - - let mut s1 = create_string(s0); + let mut s1 = create_string(); println!("{} == `{}`", stringify!(s1), s1); @@ -14,9 +12,10 @@ fn main() { println!("{} == `{}`", stringify!(s1), s1); } -///`create_string()` no longer takes `s: String` as argument +/// `create_string()` nu mai primește un argument `s: String` fn create_string() -> String { - let mut s = s; + let mut s = String::from("Hello"); // Creăm stringul în funcție s } + diff --git a/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/01.rs b/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/01.rs index 76c3ddc..52c34a9 100644 --- a/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/01.rs +++ b/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/01.rs @@ -4,8 +4,8 @@ fn main() { let mut x = 100; let y = &mut x; - let z = &mut x; *y += 100; + let z = &mut x; *z += 1000; assert_eq!(x, 1200); } diff --git a/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/02.rs b/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/02.rs index 3e4f8a6..e6384c4 100644 --- a/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/02.rs +++ b/2-foundations-of-rust/2-ownership-and-references/2-borrowing/src/bin/02.rs @@ -3,19 +3,20 @@ fn main() { let data = "Rust is great!".to_string(); - get_char(data); + get_char(&data); - string_uppercase(&data); + string_uppercase(data); } // Should not take ownership -fn get_char(data: String) -> char { +fn get_char(data: &String) -> char { data.chars().last().unwrap() } // Should take ownership -fn string_uppercase(mut data: &String) { - data = &data.to_uppercase(); +fn string_uppercase(mut data: String) { + data = data.to_uppercase(); println!("{}", data); } + diff --git a/2-foundations-of-rust/3-advanced-syntax/1-error-propagation/src/main.rs b/2-foundations-of-rust/3-advanced-syntax/1-error-propagation/src/main.rs index 5ded7bc..cfbbfb8 100644 --- a/2-foundations-of-rust/3-advanced-syntax/1-error-propagation/src/main.rs +++ b/2-foundations-of-rust/3-advanced-syntax/1-error-propagation/src/main.rs @@ -19,32 +19,44 @@ use std::io::{self, BufRead, BufReader, Lines}; //change this into: //fn read_lines(filename: &str) -> Result>, io::Error> { -fn read_lines(filename: &str) -> Lines> { - let file = File::open(filename).unwrap(); // this can easily fail - BufReader::new(file).lines() +fn read_lines(filename: &str) -> Result>, io::Error> { + let file = File::open(filename)?; + Ok(BufReader::new(file).lines()) } //change this into: //fn count_bytes_and_lines(filename: &str) -> Result<(usize, usize, usize), io::Error> { -fn count_bytes_and_lines(filename: &str) -> (usize, usize, usize) { - let lines = read_lines(filename); +fn count_bytes_and_lines(filename: &str) -> Result<(usize, usize, usize), io::Error> { + let lines = read_lines(filename)?; let mut line_count = 0; let mut word_count = 0; let mut byte_count = 0; + for line in lines { - let text = line.unwrap(); // this will usually not fail + let text = line?; line_count += 1; word_count += text.split_whitespace().count(); byte_count += text.len(); } - (line_count, word_count, byte_count) + Ok((line_count, word_count, byte_count)) } fn main() { let args: Vec = env::args().collect(); + if args.len() < 2 { + eprintln!("Usage: {} ", args[0]); + return; + } + let filename = &args[1]; - let (lines, words, bytes) = count_bytes_and_lines(filename); - println!("{filename}: {lines} lines, {words} words, {bytes} bytes"); + match count_bytes_and_lines(filename) { + Ok((lines, words, bytes)) => { + println!("{filename}: {lines} lines, {words} words, {bytes} bytes"); + } + Err(e) => { + eprintln!("Error processing file '{}': {}", filename, e); + } + } } diff --git a/2-foundations-of-rust/3-advanced-syntax/2-error-handling/src/main.rs b/2-foundations-of-rust/3-advanced-syntax/2-error-handling/src/main.rs index 0ebb167..b1b2fe7 100644 --- a/2-foundations-of-rust/3-advanced-syntax/2-error-handling/src/main.rs +++ b/2-foundations-of-rust/3-advanced-syntax/2-error-handling/src/main.rs @@ -21,34 +21,49 @@ // NOTE: You will (hopefully) discover that "?" doesn't work in this context, and the resulting code // is a bit explicit about the errors --- we can solve that with traits, next week! -use std::io::{BufRead, self, Write}; +use std::io::{self, BufRead, Write}; #[derive(Debug)] -enum MyError{ InvalidName,IOError( io::Error), +enum MyError { + InvalidName, + IOError(io::Error), } -fn get_username( ) --> String -{ +fn get_username() -> Result { print!("Username: "); - io::stdout().flush(); + io::stdout().flush().map_err(MyError::IOError)?; - let mut input=String::new(); - io::stdin().lock().read_line(&mut input); input=input.trim().to_string(); + let mut input = String::new(); + io::stdin().lock().read_line(&mut input).map_err(MyError::IOError)?; + input = input.trim().to_string(); - for c in input.chars() - { - if !char::is_alphabetic(c) { panic!("that's not a valid name, try again"); } + if input.is_empty() { + return Err(MyError::InvalidName); } -if input.is_empty() { -panic!("that's not a valid name, try again"); -} + for c in input.chars() { + if !char::is_alphabetic(c) { + return Err(MyError::InvalidName); + } + } - input + Ok(input) } fn main() { - let name=get_username(); - println!("Hello {name}!") + loop { + match get_username() { + Ok(name) => { + println!("Hello {name}!"); + break; + } + Err(MyError::InvalidName) => { + eprintln!("That's not a valid name, try again."); + } + Err(MyError::IOError(e)) => { + eprintln!("An I/O error occurred: {}", e); + break; + } + } + } } diff --git a/2-foundations-of-rust/3-advanced-syntax/3-slices/src/main.rs b/2-foundations-of-rust/3-advanced-syntax/3-slices/src/main.rs index a4d5324..d40ee49 100644 --- a/2-foundations-of-rust/3-advanced-syntax/3-slices/src/main.rs +++ b/2-foundations-of-rust/3-advanced-syntax/3-slices/src/main.rs @@ -8,27 +8,23 @@ /// Merge two array slices (that have to be sorted) into a vector fn merge(a: &[i32], b: &[i32]) -> Vec { - let mut dest = Vec::new(); + let mut dest = Vec::with_capacity(a.len() + b.len());y - let a_idx = 0; - let b_idx = 0; + let mut a_idx = 0; + let mut b_idx = 0; while a_idx < a.len() && b_idx < b.len() { if a[a_idx] <= b[b_idx] { dest.push(a[a_idx]); - a_idx += 1 + a_idx += 1; } else { dest.push(b[b_idx]); - b_idx += 1 + b_idx += 1; } } - for elem in a[a_idx..] { - dest.push(elem) - } - for elem in b[b_idx..] { - dest.push(elem) - } + dest.extend_from_slice(&a[a_idx..]); + dest.extend_from_slice(&b[b_idx..]); dest } @@ -36,8 +32,10 @@ fn merge(a: &[i32], b: &[i32]) -> Vec { /// Take an array slice, and sort into a freshly constructed vector using the above function fn merge_sort(data: &[i32]) -> Vec { if data.len() > 1 { - // implement this - todo!() + let mid = data.len() / 2; + let left = merge_sort(&data[..mid]); + let right = merge_sort(&data[mid..]); + merge(&left, &right) } else { data.to_vec() } @@ -49,7 +47,7 @@ fn read_numbers() -> Vec { let mut result = Vec::new(); for line in io::stdin().lines().flatten() { for word in line.split_whitespace() { - result.push(word.parse().unwrap()) + result.push(word.parse().unwrap()); } } @@ -59,11 +57,11 @@ fn read_numbers() -> Vec { fn main() { let input = read_numbers(); println!("Data to be sorted:"); - println!("{input:?}"); + println!("{:?}", input); let sorted_input = merge_sort(&input); println!("Sorted data:"); - println!("{sorted_input:?}"); + println!("{:?}", sorted_input); } // you can run these automatic tests by typing 'cargo test' @@ -73,10 +71,10 @@ mod test { #[test] fn test_sort() { - assert_eq!(merge_sort(&[]), vec![]); - assert_eq!(merge_sort(&[5]), vec![5]); - assert_eq!(merge_sort(&[1,2,3]), vec![1,2,3]); - assert_eq!(merge_sort(&[47,42,5,1]), vec![1,5,42,47]); - assert_eq!(merge_sort(&[6,47,42,5,1,123]), vec![1,5,6,42,47,123]); + assert_eq!(merge_sort(&[]), vec![]); + assert_eq!(merge_sort(&[5]), vec![5]); + assert_eq!(merge_sort(&[1, 2, 3]), vec![1, 2, 3]); + assert_eq!(merge_sort(&[47, 42, 5, 1]), vec![1, 5, 42, 47]); + assert_eq!(merge_sort(&[6, 47, 42, 5, 1, 123]), vec![1, 5, 6, 42, 47, 123]); } } diff --git a/2-foundations-of-rust/3-advanced-syntax/4-ring-buffer/src/main.rs b/2-foundations-of-rust/3-advanced-syntax/4-ring-buffer/src/main.rs index 95d8475..e7e8f1e 100644 --- a/2-foundations-of-rust/3-advanced-syntax/4-ring-buffer/src/main.rs +++ b/2-foundations-of-rust/3-advanced-syntax/4-ring-buffer/src/main.rs @@ -18,54 +18,72 @@ // - add a method "has_room" so that "queue.has_room()" is true if and only if writing to the queue will succeed // - add a method "peek" so that "queue.peek()" returns the same thing as "queue.read()", but leaves the element in the queue +use std::boxed::Box; + struct RingBuffer { - data: [u8; 16], + data: Box<[u8]>, start: usize, end: usize, + size: usize, } impl RingBuffer { - fn new() -> RingBuffer { + fn new(size: usize) -> RingBuffer { RingBuffer { - data: [0; 16], + data: make_box(size), start: 0, end: 0, + size, } } /// This function tries to read a value from the queue and returns Some(value) if this succeeds, /// it returns None if the queue was empty - fn read(&mut self) -> Option { - todo!() + if self.start == self.end { + None + } else { + let value = self.data[self.start]; + self.start = (self.start + 1) % self.size; + Some(value) + } } /// This function tries to put `value` on the queue; and returns true if this succeeds /// It returns false if writing to the queue failed (which can happen if there is not enough room) - fn write(&mut self, value: u8) -> bool { - self.data[self.end] = value; - let pos = (self.end + 1) % self.data.len(); - if pos == self.start { - // the buffer can hold no more new data + let next_pos = (self.end + 1) % self.size; + if next_pos == self.start { false } else { - self.end = pos; - + self.data[self.end] = value; + self.end = next_pos; true } } + + /// This function checks if there is room to write in the buffer + fn has_room(&self) -> bool { + (self.end + 1) % self.size != self.start + } + + /// This function allows peeking the next element without removing it from the queue + fn peek(&self) -> Option { + if self.start == self.end { + None + } else { + Some(self.data[self.start]) + } + } } /// This function creates an "owned slice" a user-selectable size by allocating it as a vector (filled with zeros) using vec![], and then turning it /// into a Box<[u8]> using the into_boxed_slice() method, see https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_boxed_slice - fn make_box(reqsize: usize) -> Box<[u8]> { vec![0; reqsize].into_boxed_slice() } /// This is a fun extra bit: by defining an "iterator", a ring buffer we defined ourselves can be used in for loops! (We will explain this feature in a later module!) - impl Iterator for RingBuffer { type Item = u8; @@ -75,13 +93,25 @@ impl Iterator for RingBuffer { } fn main() { - let mut queue = RingBuffer::new(); - assert!(queue.write(1)); - assert!(queue.write(2)); - assert!(queue.write(3)); - assert!(queue.write(4)); - assert!(queue.write(5)); - for elem in queue { + let mut queue = RingBuffer::new(16); + for i in 1..=10 { + assert!(queue.write(i)); + } + assert_eq!(queue.peek(), Some(1)); + assert!(queue.has_room()); + + for elem in queue.by_ref() { println!("{elem}"); } + + assert_eq!(queue.read(), None); + + for i in 11..=15 { + assert!(queue.write(i)); + } + + while let Some(value) = queue.read() { + println!("Read: {value}"); + } } + diff --git a/2-foundations-of-rust/4-traits-and-generics/1-local-storage-vec/src/lib.rs b/2-foundations-of-rust/4-traits-and-generics/1-local-storage-vec/src/lib.rs index 6d71caf..d80f0aa 100644 --- a/2-foundations-of-rust/4-traits-and-generics/1-local-storage-vec/src/lib.rs +++ b/2-foundations-of-rust/4-traits-and-generics/1-local-storage-vec/src/lib.rs @@ -2,9 +2,13 @@ /// but is moved to the heap to grow larger if needed. /// This list is generic over the items it contains as well as the /// size of its buffer if it's on the stack. + pub enum LocalStorageVec { - // TODO add some variants containing data - // to make the compiler happy + Stack { + buf: [T; N], + len: usize, + }, + Heap(Vec), } // **Below `From` implementation is used in the tests and are therefore given. However, @@ -25,7 +29,7 @@ where if N <= M { // In this case, the passed array should fit on the stack. - // We crate an `Iterator` of the passed array, + // We create an `Iterator` of the passed array, let mut it = array.into_iter(); Self::Stack { // This is a trick for copying an array into another one that's @@ -41,19 +45,25 @@ where len: N, } } else { - // If the passed array does not fit, we'll resort to moving it to the heap instead Self::Heap(Vec::from(array)) } } } +impl From> for LocalStorageVec +where T: Default, +{ + fn from(new: Vec) -> Self { + Self::Heap(new) + } +} + #[cfg(test)] mod test { use crate::LocalStorageVec; #[test] - // Don't remove the #[ignore] attribute or your tests will take forever! - #[ignore = "This test is just to validate the definition of `LocalStorageVec`. If it compiles, all is OK"] + #[ignore] #[allow(unreachable_code, unused_variables)] fn it_compiles() { // Here's a trick to 'initialize' a type while not actually @@ -76,20 +86,19 @@ mod test { } } } +} // Uncomment me for part B - // #[test] - // fn it_from_vecs() { + #[test] + fn it_from_vecs() { // // The `vec!` macro creates a `Vec` in a way that resembles // // array-initialization syntax. - // let vec: LocalStorageVec = LocalStorageVec::from(vec![1, 2, 3]); + let vec: LocalStorageVec = LocalStorageVec::from(vec![1, 2, 3]); // // Assert that the call to `from` indeed yields a `Heap` variant - // assert!(matches!(vec, LocalStorageVec::Heap(_))); - // - // let vec: LocalStorageVec = LocalStorageVec::from(vec![1, 2, 3]); - // - // assert!(matches!(vec, LocalStorageVec::Heap(_))); - // } + assert!(matches!(vec, LocalStorageVec::Heap(_))); + let vec: LocalStorageVec = LocalStorageVec::from(vec![1, 2, 3]); + assert!(matches!(vec, LocalStorageVec::Heap(_))); + } // Uncomment me for part C // #[test] @@ -280,4 +289,3 @@ mod test { // let chunks = vec.chunks_mut(4); // let slice: &mut [_] = vec.deref_mut(); // } -} diff --git a/README.md b/README.md index 3a518ad..bec3a92 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Open in Codespaces](https://classroom.github.com/assets/launch-codespace-2972f46106e565e64193e422d61a12cf1da4916b45550586e14ef0a7c637dd04.svg)](https://classroom.github.com/open-in-codespaces?assignment_repo_id=16472767) # Labs Please open each folder separately to benefit from Rust Analyzer.