Skip to content
Snippets Groups Projects
Commit dd9f8850 authored by Michaël El Kharroubi's avatar Michaël El Kharroubi :satellite:
Browse files

Merge branch 'part07' into 'main'

Adds part07 on the use of Vec and Error Handling

See merge request !12
parents 609bfc51 111d3f65
No related branches found
No related tags found
1 merge request!12Adds part07 on the use of Vec and Error Handling
Pipeline #25319 passed
[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]
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!();
}
/*!
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);
}
}
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(())
}
// 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
}
}
}
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
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment