From a30193f19b098af88344ae66caad6bbc62fb1d76 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:15:14 +0000 Subject: [PATCH 1/5] Setting up GitHub Classroom Feedback From 8fc025df938843de3e0bdcbb2411635634b76324 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:15:17 +0000 Subject: [PATCH 2/5] add online IDE url --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3a518ad..cbfd6e3 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=16672664) # Labs Please open each folder separately to benefit from Rust Analyzer. From 7ac6eecbcc163ceda5ddf9b005f318485a0d6656 Mon Sep 17 00:00:00 2001 From: Peter Arthur Date: Mon, 4 Nov 2024 19:57:20 +0200 Subject: [PATCH 3/5] Al doilea si al treilea laborator --- .../1-move-semantics/src/bin/02.rs | 4 +- .../1-move-semantics/src/bin/03.rs | 2 +- .../1-move-semantics/src/bin/04.rs | 6 +- .../2-borrowing/src/bin/01.rs | 2 +- .../2-borrowing/src/bin/02.rs | 10 +-- .../1-error-propagation/src/main.rs | 68 +++++++++++++------ .../2-error-handling/src/main.rs | 56 ++++++++++----- .../3-advanced-syntax/3-slices/src/main.rs | 31 +++++---- 8 files changed, 118 insertions(+), 61 deletions(-) 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..6819dae 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); 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..54f36e9 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,7 +12,7 @@ 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..df5f4e5 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,9 @@ //! function. fn main() { - let s0 = String::new(); + //let s0 = String::new(); - let mut s1 = create_string(s0); + let mut s1 = create_string(); println!("{} == `{}`", stringify!(s1), s1); @@ -16,7 +16,7 @@ fn main() { ///`create_string()` no longer takes `s: String` as argument fn create_string() -> String { - let mut s = s; + let s = String::from("Hello"); 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..7bd2116 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..884fc5a 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,19 @@ 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..c47553c 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 @@ -18,33 +18,63 @@ use std::fs::File; 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> { +//fn read_lines(filename: &str) -> Lines> { + let file = File::open(filename); // this can easily fail + match file { + Err(e) => return Err(e), + Ok(f) => { + return Ok(BufReader::new(f).lines()); + } + } + //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) { +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); - 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 - line_count += 1; - word_count += text.split_whitespace().count(); - byte_count += text.len(); - } + match lines { + Err(e) => { + //eprintln!("Error reading file: {}", e); + return Err(e); + } + Ok(l) => { + let mut line_count = 0; + let mut word_count = 0; + let mut byte_count = 0; + for line in l { + let text = line; + match text { + Err(e) => { + //eprintln!("Error reading line: {}", e); + return Err(e); + } + Ok(t) => { + line_count += 1; + word_count += t.split_whitespace().count(); + byte_count += t.len(); + } + } + } - (line_count, word_count, byte_count) + Ok((line_count, word_count, byte_count)) + } + } + } fn main() { let args: Vec = env::args().collect(); let filename = &args[1]; - - let (lines, words, bytes) = count_bytes_and_lines(filename); - println!("{filename}: {lines} lines, {words} words, {bytes} bytes"); + let result = count_bytes_and_lines(filename); + match result { + Err(e) => { + eprintln!("Error counting bytes and lines: {}", e); + return; + } + Ok((lines, words, bytes)) => { + println!("{filename}: {lines} lines, {words} words, {bytes} bytes"); + } + } } 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..e445eb2 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 @@ -24,31 +24,55 @@ use std::io::{BufRead, self, 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(); + if let Err(e) = io::stdout().flush() { + return Err(MyError::IOError(e)); + } let mut input=String::new(); - io::stdin().lock().read_line(&mut input); input=input.trim().to_string(); + match io::stdin().lock().read_line(&mut input) { + Err(e) => return Err(MyError::IOError(e)), + _ => { + input = input.trim().to_string(); - for c in input.chars() - { - if !char::is_alphabetic(c) { panic!("that's not a valid name, try again"); } + for c in input.chars() { + if !char::is_alphabetic(c) { + return Err(MyError::InvalidName); + } + } + + if input.is_empty() { + return Err(MyError::InvalidName); + } + + Ok(input) + }, } - -if input.is_empty() { -panic!("that's not a valid name, try again"); -} - - input + } fn main() { - let name=get_username(); + let mut name = get_username(); + while let Err(e) = name { + match e { + MyError::InvalidName => { + println!("Invalid name, please try again."); + name = get_username(); + }, + MyError::IOError(e) => { + eprintln!("IOError: {}", e); + return; + }, + } + } + + let name = name.unwrap(); + println!("Hello {name}!") } 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..4fd6372 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 @@ -10,8 +10,8 @@ fn merge(a: &[i32], b: &[i32]) -> Vec { let mut dest = Vec::new(); - 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] { @@ -23,11 +23,11 @@ fn merge(a: &[i32], b: &[i32]) -> Vec { } } - for elem in a[a_idx..] { - dest.push(elem) + for elem in &a[a_idx..] { + dest.push(*elem) } - for elem in b[b_idx..] { - dest.push(elem) + for elem in &b[b_idx..] { + dest.push(*elem) } dest @@ -36,8 +36,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,8 +51,9 @@ 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()); } + break; } result @@ -73,10 +76,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]); } } From 2bbd8577babd9ff6d02b5a4dc112242ecbb0d27d Mon Sep 17 00:00:00 2001 From: Arthur Peter Date: Mon, 18 Nov 2024 00:51:52 +0200 Subject: [PATCH 4/5] Lab4 --- .../1-error-propagation/src/main.rs | 3 -- .../4-ring-buffer/src/main.rs | 21 ++++++-- .../5-boxed-data/src/main.rs | 49 +++++++++++++------ 3 files changed, 49 insertions(+), 24 deletions(-) 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 c47553c..74540fb 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 @@ -27,7 +27,6 @@ fn read_lines(filename: &str) -> Result>, io::Error> { return Ok(BufReader::new(f).lines()); } } - //Ok(BufReader::new(file).lines()) } //change this into: @@ -36,7 +35,6 @@ fn count_bytes_and_lines(filename: &str) -> Result<(usize, usize, usize), io::Er let lines = read_lines(filename); match lines { Err(e) => { - //eprintln!("Error reading file: {}", e); return Err(e); } Ok(l) => { @@ -47,7 +45,6 @@ fn count_bytes_and_lines(filename: &str) -> Result<(usize, usize, usize), io::Er let text = line; match text { Err(e) => { - //eprintln!("Error reading line: {}", e); return Err(e); } Ok(t) => { 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..8dd9743 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 @@ -19,15 +19,15 @@ // - add a method "peek" so that "queue.peek()" returns the same thing as "queue.read()", but leaves the element in the queue struct RingBuffer { - data: [u8; 16], + data: Box<[u8]>, start: usize, end: usize, } impl RingBuffer { - fn new() -> RingBuffer { + fn new(size: usize) -> RingBuffer { RingBuffer { - data: [0; 16], + data: make_box(size), start: 0, end: 0, } @@ -37,7 +37,13 @@ impl RingBuffer { /// 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.data.len(); + Some(value) + } } /// This function tries to put `value` on the queue; and returns true if this succeeds @@ -75,7 +81,12 @@ impl Iterator for RingBuffer { } fn main() { - let mut queue = RingBuffer::new(); + let mut queue = RingBuffer::new(11); + assert!(queue.write(1)); + assert!(queue.write(2)); + assert!(queue.write(3)); + assert!(queue.write(4)); + assert!(queue.write(5)); assert!(queue.write(1)); assert!(queue.write(2)); assert!(queue.write(3)); diff --git a/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs b/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs index 12d9f0e..efc30fb 100644 --- a/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs +++ b/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs @@ -16,6 +16,8 @@ enum Expr { Const(i64), Add(Box, Box), Sub(Box, Box), + Mul(Box, Box), + Div(Box, Box), Var, Summation(Vec), } @@ -36,30 +38,39 @@ fn sub(x: Expr, y: Expr) -> Expr { } fn mul(x: Expr, y: Expr) -> Expr { - todo!() + Expr::Mul(Box::new(x), Box::new(y)) } fn div(x: Expr, y: Expr) -> Expr { - todo!() + Expr::Div(Box::new(x), Box::new(y)) } // ... -fn eval(expr: &Expr, var: i64) -> i64 { +fn eval(expr: &Expr, var: i64) -> Option { // this should return an Option use Expr::*; match expr { - Const(k) => *k, - Var => var, - Add(lhs, rhs) => eval(lhs, var) + eval(rhs, var), - Sub(lhs, rhs) => eval(lhs, var) - eval(rhs, var), + Const(k) => Some(*k), + Var => Some(var), + Add(lhs, rhs) => Some(eval(lhs, var)? + eval(rhs, var)?), + Sub(lhs, rhs) => Some(eval(lhs, var)? - eval(rhs, var)?), + Mul(lhs, rhs) => Some(eval(lhs, var)? * eval(rhs, var)?), + Div(lhs, rhs) => { + let rhs_val = eval(rhs, var)?; + if rhs_val == 0 { + None + } else { + Some(eval(lhs, var)? / rhs_val) + } + } Summation(exprs) => { let mut acc = 0; for e in exprs { - acc += eval(e, var); + acc += eval(e, var)?; } - acc + Some(acc) } } } @@ -68,7 +79,7 @@ fn main() { let test = |expr| { let value = rand::random::() as i64; println!( - "{:?} with Var = {} ==> {}", + "{:?} with Var = {} ==> {:?}", &expr, value, eval(&expr, value) @@ -81,6 +92,9 @@ fn main() { test(sub(Var, Var)); test(add(sub(Var, Const(5)), Const(5))); test(Summation(vec![Var, Const(1)])); + test(mul(Const(2), Const(3))); + test(div(Const(6), Const(2))); + test(div(Const(6), Const(0))); } #[cfg(test)] @@ -90,12 +104,15 @@ mod test { #[test] fn test_cases() { let x = 42; - assert_eq!(eval(&Const(5), x), 5); - assert_eq!(eval(&Var, x), 42); - assert_eq!(eval(&sub(Var, Const(5)), x), 37); - assert_eq!(eval(&sub(Var, Var), x), 0); - assert_eq!(eval(&add(sub(Var, Const(5)), Const(5)), x), 42); - assert_eq!(eval(&Summation(vec![Var, Const(1)]), x), 43); + assert_eq!(eval(&Const(5), x), Some(5)); + assert_eq!(eval(&Var, x), Some(42)); + assert_eq!(eval(&sub(Var, Const(5)), x), Some(37)); + assert_eq!(eval(&sub(Var, Var), x), Some(0)); + assert_eq!(eval(&add(sub(Var, Const(5)), Const(5)), x), Some(42)); + assert_eq!(eval(&Summation(vec![Var, Const(1)]), x), Some(43)); + assert_eq!(eval(&mul(Const(2), Const(3)), x), Some(6)); + assert_eq!(eval(&div(Const(6), Const(2)), x), Some(3)); + assert_eq!(eval(&div(Const(6), Const(0)), x), None); } } From fc550c7a241c9a759c63dd7ef035ee1c0b5f567c Mon Sep 17 00:00:00 2001 From: Arthur Peter Date: Mon, 9 Dec 2024 22:48:00 +0200 Subject: [PATCH 5/5] Laboratoare --- .../4-ring-buffer/src/main.rs | 18 +- .../5-boxed-data/src/main.rs | 22 +- .../1-local-storage-vec/src/lib.rs | 550 ++++++++++++------ .../1-config-reader/src/main.rs | 31 +- 4 files changed, 438 insertions(+), 183 deletions(-) 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 8dd9743..0549859 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 @@ -12,7 +12,7 @@ // 3) change the method 'new()' into 'new(size: usize)' that initializes a ring buffer of the given size (instead of a fixed size of 16); use the 'make_box' function. -// 4) in a queue that has size N, how many elements can be stored at one time? (test your answer experimentally) +// 4) in a queue that has size N, how many elements can be stored at one time? (test your answer experimentally) / R: N - 1 // 5) EXTRA EXERCISES: // - add a method "has_room" so that "queue.has_room()" is true if and only if writing to the queue will succeed @@ -61,6 +61,18 @@ impl RingBuffer { true } } + + fn has_room(&self) -> bool { + (self.end + 1) % self.data.len() != self.start + } + + 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 @@ -81,7 +93,7 @@ impl Iterator for RingBuffer { } fn main() { - let mut queue = RingBuffer::new(11); + let mut queue = RingBuffer::new(12); assert!(queue.write(1)); assert!(queue.write(2)); assert!(queue.write(3)); @@ -92,6 +104,8 @@ fn main() { assert!(queue.write(3)); assert!(queue.write(4)); assert!(queue.write(5)); + assert!(queue.peek() == Some(1)); + assert!(queue.has_room()); for elem in queue { println!("{elem}"); } diff --git a/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs b/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs index efc30fb..76e1079 100644 --- a/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs +++ b/2-foundations-of-rust/3-advanced-syntax/5-boxed-data/src/main.rs @@ -7,6 +7,7 @@ /// /// - We have added the form "Summation(Vec)", representing the sum of a list of expressions. /// Question: why can we get away with Vec enough in that case, instead of Box> ? +/// R: Vec is enough because Vec is already a heap-allocated type, so we don't need to box it. /// /// - EXTRA: Since division can fail, the function eval needs to return an Option, where None indicates that a division by /// zero has occurred. Can you change the code so that that errors are propagated correctly? (hint: use the ? syntax). @@ -20,6 +21,7 @@ enum Expr { Div(Box, Box), Var, Summation(Vec), + Signma(Box, Box), } // inject these two identifiers directly into the current namespace @@ -45,6 +47,10 @@ fn div(x: Expr, y: Expr) -> Expr { Expr::Div(Box::new(x), Box::new(y)) } +fn sigma(x: Expr, y: Expr) -> Expr { + Expr::Signma(Box::new(x), Box::new(y)) +} + // ... fn eval(expr: &Expr, var: i64) -> Option { @@ -72,6 +78,19 @@ fn eval(expr: &Expr, var: i64) -> Option { } Some(acc) } + + Signma(lhs, rhs) => { + if eval(lhs, var)? > eval(rhs, var)? { + None + } else { + let mut acc = 0; + for i in eval(lhs, var)?..=eval(rhs, var)? { + acc += i; + } + Some(acc) + } + + } } } @@ -94,7 +113,8 @@ fn main() { test(Summation(vec![Var, Const(1)])); test(mul(Const(2), Const(3))); test(div(Const(6), Const(2))); - test(div(Const(6), Const(0))); + test(div(Const(6), Const(0))); + test(sigma(Const(1), Const(6))); } #[cfg(test)] 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..92ecd10 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,17 @@ /// 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. +use std::ops::Index; + +#[derive(Debug)] 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, @@ -47,6 +55,190 @@ where } } +impl From> for LocalStorageVec +where + T: Default, +{ + fn from(array: Vec) -> Self { + Self::Heap(array) + } +} + +impl LocalStorageVec +where + T: Default + std::clone::Clone +{ + + pub fn new() -> Self { + Self::Stack { + buf: [(); N].map(|_| Default::default()), + len: 0, + } + } + + pub fn as_ref(&self) -> &[T] { + match self { + LocalStorageVec::Stack { buf, len } => &buf[..*len], + LocalStorageVec::Heap(v) => v.as_ref(), + } + } + + pub fn as_mut(&mut self) -> &mut [T] { + match self { + LocalStorageVec::Stack { buf, len } => &mut buf[..*len], + LocalStorageVec::Heap(v) => v.as_mut(), + } + } + + pub fn len(&self) -> usize { + match self { + LocalStorageVec::Stack { len, .. } => *len, + LocalStorageVec::Heap(v) => v.len(), + } + } + + pub fn push(&mut self, value: T) { + match self { + LocalStorageVec::Stack { buf, len } => { + if *len < N { + buf[*len] = value; + *len += 1; + } else { + *self = LocalStorageVec::Heap(buf.clone().to_vec()); + self.push(value); + + } + } + LocalStorageVec::Heap(v) => v.push(value), + } + } + + pub fn pop(&mut self) -> Option { + match self { + LocalStorageVec::Stack { buf, len } => { + if *len == 0 { + None + } else { + *len -= 1; + Some(buf[*len].clone()) + } + } + LocalStorageVec::Heap(v) => v.pop(), + } + } + + pub fn insert(&mut self, index: usize, value: T) { + match self { + LocalStorageVec::Stack { buf, len } => { + if *len < N { + *len += 1; + for i in (index..*len).rev() { + buf[i] = buf[i - 1].clone(); + } + buf[index] = value; + } else { + *self = LocalStorageVec::Heap(buf.clone().to_vec()); + self.insert(index, value); + } + } + LocalStorageVec::Heap(v) => v.insert(index, value), + } + } + + pub fn remove(&mut self, index: usize) -> T { + match self { + LocalStorageVec::Stack { buf, len } => { + let value = buf[index].clone(); + for i in index..*len - 1 { + buf[i] = buf[i + 1].clone(); + } + *len -= 1; + value + } + LocalStorageVec::Heap(v) => v.remove(index), + } + } + + pub fn clear(&mut self) { + match self { + LocalStorageVec::Stack { len, .. } => *len = 0, + LocalStorageVec::Heap(v) => v.clear(), + } + } + + pub fn into_iter(self) -> std::vec::IntoIter { + match self { + LocalStorageVec::Stack { buf, len } => buf[..len].to_vec().into_iter(), + LocalStorageVec::Heap(v) => v.into_iter(), + } + } + + pub fn iter(&self) -> std::slice::Iter { + self.as_ref().iter() + } + + pub fn chunks(&self, chunk_size: usize) -> std::slice::Chunks { + self.as_ref().chunks(chunk_size) + } + + pub fn chunks_mut(&mut self, chunk_size: usize) -> std::slice::ChunksMut { + self.as_mut().chunks_mut(chunk_size) + } + + pub fn deref(&self) -> &[T] { + self.as_ref() + } + + pub fn deref_mut(&mut self) -> &mut [T] { + self.as_mut() + } + +} + +impl Index for LocalStorageVec { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + match self { + LocalStorageVec::Stack { buf, len: _ } => &buf[index], + LocalStorageVec::Heap(v) => &v[index], + } + } +} + +impl Index> for LocalStorageVec { + type Output = [T]; + + fn index(&self, index: std::ops::RangeTo) -> &Self::Output { + match self { + LocalStorageVec::Stack { buf, len: _ } => &buf[..index.end], + LocalStorageVec::Heap(v) => &v[..index.end], + } + } +} + +impl Index> for LocalStorageVec { + type Output = [T]; + + fn index(&self, index: std::ops::Range) -> &Self::Output { + match self { + LocalStorageVec::Stack { buf, len: _ } => &buf[index.start..index.end], + LocalStorageVec::Heap(v) => &v[index], + } + } +} + +impl Index> for LocalStorageVec { + type Output = [T]; + + fn index(&self, index: std::ops::RangeFrom) -> &Self::Output { + match self { + LocalStorageVec::Stack { buf, len } => &buf[index.start..*len], + LocalStorageVec::Heap(v) => &v[index.start..], + } + } +} + #[cfg(test)] mod test { use crate::LocalStorageVec; @@ -77,207 +269,207 @@ mod test { } } - // Uncomment me for part B - // #[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]); - // // 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(_))); - // } + //Uncomment me for part B + #[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]); + // 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(_))); + } // Uncomment me for part C - // #[test] - // fn it_as_refs() { - // let vec: LocalStorageVec = LocalStorageVec::from([0; 128]); - // let slice: &[i32] = vec.as_ref(); - // assert!(slice.len() == 128); - // let vec: LocalStorageVec = LocalStorageVec::from([0; 128]); - // let slice: &[i32] = vec.as_ref(); - // assert!(slice.len() == 128); - // - // let mut vec: LocalStorageVec = LocalStorageVec::from([0; 128]); - // let slice_mut: &[i32] = vec.as_mut(); - // assert!(slice_mut.len() == 128); - // let mut vec: LocalStorageVec = LocalStorageVec::from([0; 128]); - // let slice_mut: &[i32] = vec.as_mut(); - // assert!(slice_mut.len() == 128); - // } + #[test] + fn it_as_refs() { + let vec: LocalStorageVec = LocalStorageVec::from([0; 128]); + let slice: &[i32] = vec.as_ref(); + assert!(slice.len() == 128); + let vec: LocalStorageVec = LocalStorageVec::from([0; 128]); + let slice: &[i32] = vec.as_ref(); + assert!(slice.len() == 128); + + let mut vec: LocalStorageVec = LocalStorageVec::from([0; 128]); + let slice_mut: &[i32] = vec.as_mut(); + assert!(slice_mut.len() == 128); + let mut vec: LocalStorageVec = LocalStorageVec::from([0; 128]); + let slice_mut: &[i32] = vec.as_mut(); + assert!(slice_mut.len() == 128); + } // Uncomment me for part D - // #[test] - // fn it_constructs() { - // let vec: LocalStorageVec = LocalStorageVec::new(); - // // Assert that the call to `new` indeed yields a `Stack` variant with zero length - // assert!(matches!(vec, LocalStorageVec::Stack { buf: _, len: 0 })); - // } + #[test] + fn it_constructs() { + let vec: LocalStorageVec = LocalStorageVec::new(); + // Assert that the call to `new` indeed yields a `Stack` variant with zero length + assert!(matches!(vec, LocalStorageVec::Stack { buf: _, len: 0 })); + } // Uncomment me for part D - // #[test] - // fn it_lens() { - // let vec: LocalStorageVec<_, 3> = LocalStorageVec::from([0, 1, 2]); - // assert_eq!(vec.len(), 3); - // let vec: LocalStorageVec<_, 2> = LocalStorageVec::from([0, 1, 2]); - // assert_eq!(vec.len(), 3); - // } + #[test] + fn it_lens() { + let vec: LocalStorageVec<_, 3> = LocalStorageVec::from([0, 1, 2]); + assert_eq!(vec.len(), 3); + let vec: LocalStorageVec<_, 2> = LocalStorageVec::from([0, 1, 2]); + assert_eq!(vec.len(), 3); + } // Uncomment me for part D - // #[test] - // fn it_pushes() { - // let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::new(); - // for value in 0..128 { - // vec.push(value); - // } - // assert!(matches!(vec, LocalStorageVec::Stack { len: 128, .. })); - // for value in 128..256 { - // vec.push(value); - // } - // assert!(matches!(vec, LocalStorageVec::Heap(v) if v.len() == 256)) - // } + #[test] + fn it_pushes() { + let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::new(); + for value in 0..128 { + vec.push(value); + } + assert!(matches!(vec, LocalStorageVec::Stack { len: 128, .. })); + for value in 128..256 { + vec.push(value); + } + assert!(matches!(vec, LocalStorageVec::Heap(v) if v.len() == 256)) + } // Uncomment me for part D - // #[test] - // fn it_pops() { - // let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 128]); - // for _ in 0..128 { - // assert_eq!(vec.pop(), Some(0)) - // } - // assert_eq!(vec.pop(), None); - // - // let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 256]); - // for _ in 0..256 { - // assert_eq!(vec.pop(), Some(0)) - // } - // assert_eq!(vec.pop(), None); - // - // let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from(vec![0; 256]); - // for _ in 0..256 { - // assert_eq!(vec.pop(), Some(0)) - // } - // assert_eq!(vec.pop(), None); - // } + #[test] + fn it_pops() { + let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 128]); + for _ in 0..128 { + assert_eq!(vec.pop(), Some(0)) + } + assert_eq!(vec.pop(), None); + + let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 256]); + for _ in 0..256 { + assert_eq!(vec.pop(), Some(0)) + } + assert_eq!(vec.pop(), None); + + let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from(vec![0; 256]); + for _ in 0..256 { + assert_eq!(vec.pop(), Some(0)) + } + assert_eq!(vec.pop(), None); + } // Uncomment me for part D - // #[test] - // fn it_inserts() { - // let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2]); - // vec.insert(1, 3); - // assert!(matches!( - // vec, - // LocalStorageVec::Stack { - // buf: [0, 3, 1, 2], - // len: 4 - // } - // )); - // - // let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2, 3]); - // vec.insert(1, 3); - // assert!(matches!(vec, LocalStorageVec::Heap { .. })); - // assert_eq!(vec.as_ref(), &[0, 3, 1, 2, 3]); - // - // let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2, 3, 4]); - // vec.insert(1, 3); - // assert!(matches!(vec, LocalStorageVec::Heap { .. })); - // assert_eq!(vec.as_ref(), &[0, 3, 1, 2, 3, 4]) - // } + #[test] + fn it_inserts() { + let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2]); + vec.insert(1, 3); + assert!(matches!( + vec, + LocalStorageVec::Stack { + buf: [0, 3, 1, 2], + len: 4 + } + )); + + let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2, 3]); + vec.insert(1, 3); + assert!(matches!(vec, LocalStorageVec::Heap { .. })); + assert_eq!(vec.as_ref(), &[0, 3, 1, 2, 3]); + + let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2, 3, 4]); + vec.insert(1, 3); + assert!(matches!(vec, LocalStorageVec::Heap { .. })); + assert_eq!(vec.as_ref(), &[0, 3, 1, 2, 3, 4]) + } // Uncomment me for part D - // #[test] - // fn it_removes() { - // let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2]); - // let elem = vec.remove(1); - // dbg!(&vec); - // assert!(matches!( - // vec, - // LocalStorageVec::Stack { - // buf: [0, 2, _, _], - // len: 2 - // } - // )); - // assert_eq!(elem, 1); - // - // let mut vec: LocalStorageVec<_, 2> = LocalStorageVec::from([0, 1, 2]); - // let elem = vec.remove(1); - // assert!(matches!(vec, LocalStorageVec::Heap(..))); - // assert_eq!(vec.as_ref(), &[0, 2]); - // assert_eq!(elem, 1); - // } + #[test] + fn it_removes() { + let mut vec: LocalStorageVec<_, 4> = LocalStorageVec::from([0, 1, 2]); + let elem = vec.remove(1); + dbg!(&vec); + assert!(matches!( + vec, + LocalStorageVec::Stack { + buf: [0, 2, _, _], + len: 2 + } + )); + assert_eq!(elem, 1); + + let mut vec: LocalStorageVec<_, 2> = LocalStorageVec::from([0, 1, 2]); + let elem = vec.remove(1); + assert!(matches!(vec, LocalStorageVec::Heap(..))); + assert_eq!(vec.as_ref(), &[0, 2]); + assert_eq!(elem, 1); + } // Uncomment me for part D - // #[test] - // fn it_clears() { - // let mut vec: LocalStorageVec<_, 10> = LocalStorageVec::from([0, 1, 2, 3]); - // assert!(matches!(vec, LocalStorageVec::Stack { buf: _, len: 4 })); - // vec.clear(); - // assert_eq!(vec.len(), 0); - // - // let mut vec: LocalStorageVec<_, 3> = LocalStorageVec::from([0, 1, 2, 3]); - // assert!(matches!(vec, LocalStorageVec::Heap(_))); - // vec.clear(); - // assert_eq!(vec.len(), 0); - // } + #[test] + fn it_clears() { + let mut vec: LocalStorageVec<_, 10> = LocalStorageVec::from([0, 1, 2, 3]); + assert!(matches!(vec, LocalStorageVec::Stack { buf: _, len: 4 })); + vec.clear(); + assert_eq!(vec.len(), 0); + + let mut vec: LocalStorageVec<_, 3> = LocalStorageVec::from([0, 1, 2, 3]); + assert!(matches!(vec, LocalStorageVec::Heap(_))); + vec.clear(); + assert_eq!(vec.len(), 0); + } // Uncomment me for part E - // #[test] - // fn it_iters() { - // let vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 32]); - // let mut iter = vec.into_iter(); - // for item in &mut iter { - // assert_eq!(item, 0); - // } - // assert_eq!(iter.next(), None); - // - // let vec: LocalStorageVec<_, 128> = LocalStorageVec::from(vec![0; 128]); - // let mut iter = vec.into_iter(); - // for item in &mut iter { - // assert_eq!(item, 0); - // } - // assert_eq!(iter.next(), None); - // } + #[test] + fn it_iters() { + let vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 32]); + let mut iter = vec.into_iter(); + for item in &mut iter { + assert_eq!(item, 0); + } + assert_eq!(iter.next(), None); + + let vec: LocalStorageVec<_, 128> = LocalStorageVec::from(vec![0; 128]); + let mut iter = vec.into_iter(); + for item in &mut iter { + assert_eq!(item, 0); + } + assert_eq!(iter.next(), None); + } // Uncomment me for part F - // #[test] - // fn it_indexes() { - // let vec: LocalStorageVec = LocalStorageVec::from([0, 1, 2, 3, 4, 5]); - // assert_eq!(vec[1], 1); - // assert_eq!(vec[..2], [0, 1]); - // assert_eq!(vec[4..], [4, 5]); - // assert_eq!(vec[1..3], [1, 2]); - // } + #[test] + fn it_indexes() { + let vec: LocalStorageVec = LocalStorageVec::from([0, 1, 2, 3, 4, 5]); + assert_eq!(vec[1], 1); + assert_eq!(vec[..2], [0, 1]); + assert_eq!(vec[4..], [4, 5]); + assert_eq!(vec[1..3], [1, 2]); + } // Uncomment me for part H - // #[test] - // fn it_borrowing_iters() { - // let vec: LocalStorageVec = LocalStorageVec::from([ - // "0".to_owned(), - // "1".to_owned(), - // "2".to_owned(), - // "3".to_owned(), - // "4".to_owned(), - // "5".to_owned(), - // ]); - // let iter = vec.iter(); - // for _ in iter {} - // // This requires the `vec` not to be consumed by the call to `iter()` - // drop(vec); - // } + #[test] + fn it_borrowing_iters() { + let vec: LocalStorageVec = LocalStorageVec::from([ + "0".to_owned(), + "1".to_owned(), + "2".to_owned(), + "3".to_owned(), + "4".to_owned(), + "5".to_owned(), + ]); + let iter = vec.iter(); + for _ in iter {} + // This requires the `vec` not to be consumed by the call to `iter()` + drop(vec); + } // Uncomment me for part J - // #[test] - // fn it_derefs() { - // use std::ops::{Deref, DerefMut}; - // let vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 128]); - // // `chunks` is a method that's defined for slices `[T]`, that we can use thanks to `Deref` - // let chunks = vec.chunks(4); - // let slice: &[_] = vec.deref(); - // - // let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 128]); - // let chunks = vec.chunks_mut(4); - // let slice: &mut [_] = vec.deref_mut(); - // } + #[test] + fn it_derefs() { + use std::ops::{Deref, DerefMut}; + let vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 128]); + // `chunks` is a method that's defined for slices `[T]`, that we can use thanks to `Deref` + let chunks = vec.chunks(4); + let slice: &[_] = vec.deref(); + + let mut vec: LocalStorageVec<_, 128> = LocalStorageVec::from([0; 128]); + let chunks = vec.chunks_mut(4); + let slice: &mut [_] = vec.deref_mut(); + } } diff --git a/2-foundations-of-rust/5-closures-and-dynamic-dispatch/1-config-reader/src/main.rs b/2-foundations-of-rust/5-closures-and-dynamic-dispatch/1-config-reader/src/main.rs index bb37cdf..f1ef0d1 100644 --- a/2-foundations-of-rust/5-closures-and-dynamic-dispatch/1-config-reader/src/main.rs +++ b/2-foundations-of-rust/5-closures-and-dynamic-dispatch/1-config-reader/src/main.rs @@ -27,6 +27,24 @@ trait DeserializeConfig { // TODO add some types that implement `DeserializeConfig` +struct JsonFile { +} + +struct YamlFile { +} + +impl DeserializeConfig for JsonFile { + fn deserialize<'a>(&self, contents: &'a str) -> Result, Error> { + serde_json::from_str(contents).map_err(Error::Json) + } +} + +impl DeserializeConfig for YamlFile { + fn deserialize<'a>(&self, contents: &'a str) -> Result, Error> { + serde_yaml::from_str(contents).map_err(Error::Yaml) + } +} + fn main() { let mut args = std::env::args(); // Unwrapping is OK here, as UTF-8 Strings can always be converted to PathBufs @@ -45,7 +63,18 @@ fn main() { } }; - let config: Config = todo!("Deserialize `file_contents` using either serde_yaml or serde_json depending on the file extension. Use dynamic dispatch"); + let json = JsonFile {}; + let yaml = YamlFile {}; + + let config: Config = match _extension { + Some("json") => json.deserialize(&file_contents).unwrap(), + Some("yml") | Some("yaml") => yaml.deserialize(&file_contents).unwrap(), + _ => { + eprintln!("Unsupported file extension"); + return; + } + + }; println!("Config was: {config:?}"); }