gestion_erreurs

src/lib.rs

#![allow(unused)]
fn main() {
//! This crate shows us different ways of dealing with errors in a Rust program.
//! You will find examples of [Option], [Result] and [panic!].

pub mod find_minimum;
pub mod io;
pub mod minimum;

#[cfg(test)]
mod tests {
    use crate::find_minimum::{
        find_min_amongst_arrays_by_hand, find_min_amongst_arrays_qm_op, find_min_with_option,
        find_min_with_panic, find_min_with_result,
    };
    const TAB: [i32; 9] = [10, 32, 12, 43, 52, 53, 83, 2, 9];
    const TAB_B: [i32; 9] = [22, 34, 11, 4, 52, 99, 71, 13, 43];
    const TAB_EMPTY: [i32; 0] = [];
    const MIN_TAB: i32 = 2;

    #[test]
    fn test_find_min_option() {
        let min = find_min_with_option(&TAB);

        assert!(min == Some(MIN_TAB));
    }

    #[test]
    fn test_find_min_option_empty() {
        let min = find_min_with_option(&TAB_EMPTY);

        assert!(min.is_none());
    }

    #[test]
    fn test_find_min_result() {
        let min = find_min_with_result(&TAB);

        assert!(min == Ok(MIN_TAB));
    }

    #[test]
    fn test_find_min_result_empty() {
        let min = find_min_with_result(&TAB_EMPTY);

        assert!(min.is_err());
    }

    #[test]
    fn test_find_min_panic() {
        let min = find_min_with_panic(&TAB);

        assert!(min == MIN_TAB);
    }

    #[test]
    #[should_panic]
    fn test_find_min_panic_empty() {
        let _min = find_min_with_panic(&TAB_EMPTY);
    }

    #[test]
    fn test_find_min_amongst_arrays_bh() {
        let min = find_min_amongst_arrays_by_hand(&TAB, &TAB_B);

        assert!(min == Ok(MIN_TAB));
    }

    #[test]
    fn test_find_min_amongst_arrays_qm() {
        let min = find_min_amongst_arrays_qm_op(&TAB, &TAB_B);

        assert!(min == Ok(MIN_TAB));
    }

    #[test]
    fn test_find_min_amongst_arrays_bh_empty() {
        let min = find_min_amongst_arrays_by_hand(&TAB, &TAB_EMPTY);

        assert!(min.is_err());
    }

    #[test]
    fn test_find_min_amongst_arrays_qm_empty() {
        let min = find_min_amongst_arrays_qm_op(&TAB, &TAB_EMPTY);

        assert!(min.is_err());
    }
}
}

src/main.rs

use gestion_erreurs::find_minimum::{
    FindMinError::EmptyList, FindMinError::UnsupportedError, find_min_amongst_arrays_qm_op,
    find_min_with_option, find_min_with_result,
};
use gestion_erreurs::io;

fn main() {
    let tab = io::read_command_line_correct();
    println!("Among the elements in the list:");
    io::print_tab(&tab);
    let min = find_min_with_option(&tab);
    match min {
        Some(val) => print!("The minimum value is {}", val),
        None => eprintln!("There is no minimum since the list is empty"),
    }
    println!("");
    println!("");

    let tab_empty = io::read_empty_command_line();
    println!("Among the elements in the list:");
    io::print_tab(&tab_empty);

    //ANCHOR: parse_result
    let min = find_min_with_result(&tab_empty);
    match min {
        Ok(val) => print!("The minimum value is {}", val),
        Err(EmptyList) => eprintln!("The array is empty"),
        Err(UnsupportedError(msg)) => panic!("Unsupported error : {}", msg),
    }
    //ANCHOR_END: parse_result

    println!("Among the elements in the lists:");
    io::print_tab(&tab);
    io::print_tab(&tab_empty);
    let min = find_min_amongst_arrays_qm_op(&tab, &tab_empty);
    match min {
        Ok(val) => print!("The minimum value is {}", val),
        Err(EmptyList) => eprintln!("One or both arrays are empty"),
        Err(UnsupportedError(msg)) => panic!("Unsupported error : {}", msg),
    }
}

src/find_minimum.rs

//! Contains the core logic of the library, allowing to store generic values
//! (or their absence) and manipulate them.
//! We demonstrates three kind of way to deal with errors

use crate::minimum::Minimum;

// ANCHOR: find_min_error
#[derive(PartialEq)]
pub enum FindMinError {
    EmptyList,
    UnsupportedError(String),
}
// ANCHOR_END: find_min_error

use crate::find_minimum::FindMinError::EmptyList;

/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [Option::Some] containing the minimum value
/// or [Option::None] if no minimum value was found.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_option};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min_with_option(&tab);
/// assert!(min == Some(2));
/// # }
/// ```
// ANCHOR: min_with_option
pub fn find_min_with_option<T: Minimum>(tab: &[T]) -> Option<T> {
    let mut minimum = None;
    // Here, if T is Copyable, t is not moved in the loop
    for t in tab {
        minimum = Minimum::min(minimum, Some(*t));
    }
    minimum
}
// ANCHOR_END: min_with_option

/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [Result::Ok] containing the minimum value
/// or an [Result::Err] containing the error, if no minimum value was found.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_result};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min_with_result(&tab);
/// assert!(min == Ok(2));
/// # }
/// ```
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_result};
/// # fn main() {
/// let tab : [i32; 0] = [];
/// let min = find_min_with_result(&tab);
/// assert!(min.is_err());
/// # }
/// ```
// ANCHOR: min_with_result
pub fn find_min_with_result<T: Minimum>(tab: &[T]) -> Result<T, FindMinError> {
    let mut minimum = None;
    // Here, if T is Copyable, t is not moved in the loop
    for t in tab {
        minimum = Minimum::min(minimum, Some(*t));
    }

    match minimum {
        Some(val) => Ok(val),
        None => Err(EmptyList),
    }
}
// ANCHOR_END: min_with_result

/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a T which is the minimum value
/// or panics if no minimum value was found.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_panic};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min_with_panic(&tab);
/// assert!(min == 2);
/// # }
/// ```
///
/// ```should_panic
/// # use gestion_erreurs::find_minimum::{find_min_with_panic};
/// # fn main() {
/// let tab : [i32; 0] = [];
/// let _min = find_min_with_panic(&tab);
/// # }
/// ```
// ANCHOR: min_with_panic
pub fn find_min_with_panic<T: Minimum>(tab: &[T]) -> T {
    let mut minimum = None;
    // Here, if T is Copyable, t is not moved in the loop
    for t in tab {
        minimum = Minimum::min(minimum, Some(*t));
    }

    // We decide that we cannot compute the minimum of an empty array
    match minimum {
        Some(val) => val,
        None => panic!("The array is empty"),
    }
}
// ANCHOR_END: min_with_panic

/// Computes the minimum amongst two Arrays of a type T which implements the [Minimum] trait.
/// Returns a [Result::Ok] containing the minimum value
/// or an [Result::Err] containing the error, if no minimum value was found.
///
/// We deal with errors in underlying function calls without the [?] operator.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_by_hand};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b = [22, 34, 11, 4, 52, 99, 71, 13, 43];
/// let min = find_min_amongst_arrays_by_hand(&tab_a, &tab_b);
/// assert!(min == Ok(2));
/// # }
/// ```
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_by_hand};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b : [i32; 0] = [];
/// let min = find_min_amongst_arrays_by_hand(&tab_a, &tab_b);
/// assert!(min.is_err());
/// # }
/// ```
// ANCHOR: min_two_tabs_hand
pub fn find_min_amongst_arrays_by_hand<T: Minimum>(
    lhs: &[T],
    rhs: &[T],
) -> Result<T, FindMinError> {
    let min_result = find_min_with_result(lhs);
    let min_l = if let Ok(x) = min_result {
        x
    } else {
        // Since tmp is not Ok, we return the error to the caller
        return min_result;
    };

    let min_result = find_min_with_result(rhs);
    let min_r = if let Ok(x) = min_result {
        x
    } else {
        // Since tmp is not Ok, we return the error to the caller
        return min_result;
    };

    Ok(min_l.min(min_r))
}
// ANCHOR_END: min_two_tabs_hand

/// Computes the minimum amongst two Arrays of a type T which implements the [Minimum] trait.
/// Returns a [Result::Ok] containing the minimum value
/// or an [Result::Err] containing the error, if no minimum value was found.
///
/// We deal with errors in underlying function with the [?] operator.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_qm_op};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b = [22, 34, 11, 4, 52, 99, 71, 13, 43];
/// let min = find_min_amongst_arrays_qm_op(&tab_a, &tab_b);
/// assert!(min == Ok(2));
/// # }
/// ```
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_qm_op};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b : [i32; 0] = [];
/// let min = find_min_amongst_arrays_qm_op(&tab_a, &tab_b);
/// assert!(min.is_err());
/// # }
/// ```
// ANCHOR: min_two_tabs_qm
pub fn find_min_amongst_arrays_qm_op<T: Minimum>(lhs: &[T], rhs: &[T]) -> Result<T, FindMinError> {
    // The question mark operator will unpack the value if the function returns [Result::Ok]
    // or end the function and return the [Result:Err] to the caller.
    let min_l = find_min_with_result(lhs)?;
    let min_r = find_min_with_result(rhs)?;

    Ok(min_l.min(min_r))
}
// ANCHOR_END: min_two_tabs_qm

src/io.rs

#![allow(unused)]
fn main() {
//! Contains functions to interact with the user, either
//! by reading inputs from the terminal, either by writing values
//! in it.

/// Poorly emulates the parsing of a command line.
pub fn read_command_line_correct() -> [i32; 9] {
    [10, 32, 12, 43, 52, 53, 83, 2, 9]
}

/// Poorly emulates the parsing of a command line.
pub fn read_empty_command_line() -> [i32; 0] {
    []
}

/// Prints all the elements of the `tab`.
/// Tab is borrowed here
pub fn print_tab(tab: &[i32]) {
    print!("[ ");
    for t in tab {
        print!("{} ", t);
    }
    println!("]");
}
}

src/minimum.rs

#![allow(unused)]
fn main() {
//! Contains a generic trait implementation for computing the minimum between two
//! values. It is the equivalent of the `<` operator.
//!
//! # Examples
//!
//! For integers this would look like
//!
//! ```
//! # use gestion_erreurs::minimum::Minimum;
//! let one = 1;
//! let two = 2;
//! assert!(Minimum::min(one, two) == one);
//! ```

/// The [Minimum] trait computes the minimum value between two values of a type
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 }
    }
}

// ANCHOR: min_for_option
impl<T: Minimum> Minimum for Option<T> {
    fn min(self, rhs: Self) -> Self {
        match self {
            Some(val_l) => Some(match rhs {
                Some(val_r) => val_l.min(val_r),
                None => val_l,
            }),
            None => match rhs {
                Some(val_r) => Some(val_r),
                None => None,
            },
        }
    }
}
// ANCHOR_END: min_for_option

#[cfg(test)]
mod tests {
    use crate::minimum::Minimum;

    #[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);
    }
}
}