diff --git a/codes/rust_lang/part07/Cargo.toml b/codes/rust_lang/part07/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..07e37ffdda233f424bf369ce0785a9c0ada5691e --- /dev/null +++ b/codes/rust_lang/part07/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "part07" +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/codes/rust_lang/part07/src/io.rs b/codes/rust_lang/part07/src/io.rs new file mode 100644 index 0000000000000000000000000000000000000000..2eeaeb4f0201bac3b31daede9f1f2ffb2c0444d2 --- /dev/null +++ b/codes/rust_lang/part07/src/io.rs @@ -0,0 +1,35 @@ +use std::io::BufRead; + +/// Reads i32 from the command line and returns a [Vec] containing +/// these numbers. Returns errors when the parsing fails. +pub fn read_command_line() -> Result<Vec<i32>, String> { + let mut v = Vec::new(); + let stdin = std::io::stdin(); + println!("Enter a list of numbers, one per line. End with Ctrl-D (Linux) or Ctrl-Z (Windows)."); + + for line in stdin.lock().lines() { + let line = match line { + Ok(l) => l, + Err(_) => { + return Err(String::from("Could not read line")); + } + }; + + match line.trim().parse::<i32>() { + Ok(num) => v.push(num), + Err(_) => { + return Err(String::from("Could not parse integer")); + } + } + } + Ok(v) +} + +/// Prints all the elements of the `tab`. +/// Tab is borrowed here +pub fn print_tab(tab: &Vec<i32>) { + for t in tab { + print!("{} ", t); + } + println!(); +} diff --git a/codes/rust_lang/part07/src/lib.rs b/codes/rust_lang/part07/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..dd53b82629e1b15c144969d81fc4e6c075d2e4ff --- /dev/null +++ b/codes/rust_lang/part07/src/lib.rs @@ -0,0 +1,59 @@ +/*! +part07 illustrates the use of [Vec] and the Error Handling with [Option] and [Result]. +It also showcases struct enums. +*/ + +pub mod io; +mod minimum; +pub mod something_or_nothing; + +#[cfg(test)] +mod tests { + use crate::minimum::Minimum; + use crate::something_or_nothing::{find_min, SomethingOrNothing}; + + #[test] + fn test_creation() { + let n1: SomethingOrNothing<i32> = SomethingOrNothing::default(); + assert!(n1 == SomethingOrNothing::default()); + let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1); + assert!(n2 == SomethingOrNothing::new(1)); + } + + #[test] + #[should_panic] + fn test_failure_creation() { + let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1); + assert!(n2 == SomethingOrNothing::default()); + assert!(n2 == SomethingOrNothing::new(2)); + } + + #[test] + fn test_min() { + let a = vec![1, 5, -1, 2, 0, 10, 11, 0, 3]; + let min = find_min(&a); + assert!(min == SomethingOrNothing::new(-1)); + } + + #[test] + fn test_min_i32() { + let x = 5; + let y = 10; + assert_eq!(Minimum::min(x, y), x); + assert_eq!(Minimum::min(y, x), x); + assert_eq!(Minimum::min(x, x), x); + assert_eq!(Minimum::min(y, y), y); + } + + #[test] + fn test_min_something_or_nothing() { + let x = SomethingOrNothing::new(5i32); + let y = SomethingOrNothing::new(10i32); + let z = SomethingOrNothing::default(); + assert!(x.min(y) == x); + assert!(y.min(x) == x); + assert!(z.min(y) == y); + assert!(y.min(z) == y); + assert!(z.min(z) == z); + } +} diff --git a/codes/rust_lang/part07/src/main.rs b/codes/rust_lang/part07/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..addf8b4a7cbf1d35e38cc9c50a091aaafd32c147 --- /dev/null +++ b/codes/rust_lang/part07/src/main.rs @@ -0,0 +1,16 @@ +use part07::io; +use part07::something_or_nothing::find_min; + +fn main() -> Result<(), String> { + let tab = match io::read_command_line() { + Ok(tab) => tab, + Err(s) => return Err(s), + }; + println!("Among the Somethings in the list:"); + io::print_tab(&tab); + // There are alternatives to access fields of tuples + let min = find_min(&tab); + // The first field is not used therefore we can replace it with "_" + min.print(); + Ok(()) +} diff --git a/codes/rust_lang/part07/src/minimum.rs b/codes/rust_lang/part07/src/minimum.rs new file mode 100644 index 0000000000000000000000000000000000000000..7d7a654b8f2c43bc76e35616813465c6142a0bff --- /dev/null +++ b/codes/rust_lang/part07/src/minimum.rs @@ -0,0 +1,15 @@ +// If we remove Copy, we have a problem with the t in tab +// in the computation of the minimum. +pub trait Minimum: Copy { + fn min(self, rhs: Self) -> Self; +} + +impl Minimum for i32 { + fn min(self, rhs: Self) -> Self { + if self < rhs { + self + } else { + rhs + } + } +} diff --git a/codes/rust_lang/part07/src/something_or_nothing.rs b/codes/rust_lang/part07/src/something_or_nothing.rs new file mode 100644 index 0000000000000000000000000000000000000000..600bf0c6dbfbc567350a0ce74d4885bc4d07d054 --- /dev/null +++ b/codes/rust_lang/part07/src/something_or_nothing.rs @@ -0,0 +1,80 @@ +use std::fmt::Display; + +use crate::minimum::Minimum; + +/// An generic enumerated type that encapsulates and Option<T>. +#[derive(Clone, Copy)] +pub struct SomethingOrNothing<T>(Option<T>); + +impl<T: Minimum + Display> SomethingOrNothing<T> { + pub fn new(val: T) -> Self { + SomethingOrNothing(Some(val)) + } + /// A static function that prints the content of a SomethingOrNothing. + pub fn print(&self) { + match self.0 { + None => println!("Nothing."), + Some(val) => println!("Something is: {}", val), + } + } +} + +impl<T> Default for SomethingOrNothing<T> { + /// By Default a [SomethingOrNothing] is a nothing. + fn default() -> Self { + SomethingOrNothing(None) + } +} + +impl<T: PartialEq + Minimum> PartialEq for SomethingOrNothing<T> { + fn eq(&self, other: &Self) -> bool { + match (self.0, other.0) { + (None, None) => true, + (Some(lhs), Some(rhs)) => lhs == rhs, + _ => false, + } + } +} + +impl<T: Minimum + Display> Minimum for SomethingOrNothing<T> { + fn min(self, rhs: Self) -> Self { + match (self.0, rhs.0) { + (None, None) => SomethingOrNothing(None), + (Some(lhs), Some(rhs)) => SomethingOrNothing::new(lhs.min(rhs)), + (None, Some(rhs)) => SomethingOrNothing::new(rhs), + (Some(lhs), None) => SomethingOrNothing::new(lhs), + } + } +} + +/// Computes the minimum of an Array of a type T which implements the [Minimum] trait. +/// Returns a [Some] containing the the minimum value +/// or [None] if no minimum value was found. +/// +/// # Examples +/// +/// ``` +/// # use part07::something_or_nothing::{SomethingOrNothing, find_min}; +/// # fn main() { +/// let tab = vec![10, 32, 12, 43, 52, 53, 83, 2, 9]; +/// let min = find_min(&tab); +/// assert!(min == SomethingOrNothing::new(2)); +/// # } +/// ``` +/// +/// ``` +/// # use part07::something_or_nothing::{SomethingOrNothing, find_min}; +/// # fn main() { +/// let tab: Vec<i32> = vec![]; +/// let min = find_min(&tab); +/// assert!(min == SomethingOrNothing::default()); +/// # } +/// ``` +pub fn find_min<T: Minimum + Display>(tab: &Vec<T>) -> SomethingOrNothing<T> { + let mut minimum: SomethingOrNothing<T> = SomethingOrNothing(None); + // Here is T is Copyable. Which means that t is not moved in the loop + for t in tab { + minimum = minimum.min(SomethingOrNothing::new(*t)); + } + minimum +}