closures

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 binary_operator;
pub mod find;
pub mod io;

#[cfg(test)]
mod tests {
    use crate::binary_operator::*;
    use crate::find::find_with_hof;
    const TAB: [i32; 9] = [10, 32, 12, 43, 52, 53, 83, 2, 9];
    const TAB_EMPTY: [i32; 0] = [];
    const MIN_TAB: i32 = 2;
    const MAX_TAB: i32 = 83;

    #[test]
    fn test_find_with_option_min() {
        let min: Option<i32> = find_with_hof(&TAB, |x: i32, y: i32| if x <= y { x } else { y });

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

    #[test]
    fn test_find_with_option_max() {
        let max: Option<i32> = find_with_hof(&TAB, |x: i32, y: i32| if x >= y { x } else { y });

        assert!(max == Some(MAX_TAB));
    }

    #[test]
    fn test_find_with_option_empty() {
        let min: Option<i32> =
            find_with_hof(&TAB_EMPTY, |x: i32, y: i32| if x <= y { x } else { y });

        assert!(min.is_none());
    }

    #[test]
    fn test_minimum_operator() {
        let f = minimum_operator::<i32>();

        assert!(f(5, 10) == 5);
    }

    #[test]
    fn test_maximum_operator() {
        let f = maximum_operator::<i32>();

        assert!(f(5, 10) == 10);
    }

    #[test]
    fn test_sum_operator() {
        let f = sum_operator::<i32>();

        assert!(f(5, 10) == 15);
    }

    #[test]
    fn test_mul_operator() {
        let f = mul_operator::<i32>();

        assert!(f(5, 10) == 50);
    }
}
}

src/main.rs

use closures::binary_operator::{minimum_operator, sum_operator};
use closures::find::find_with_hof;
use closures::io;

fn main() {
    let tab = io::read_command_line_correct();
    println!("Among the elements in the list:");
    io::print_tab(&tab);

    //ANCHOR: min_usage
    let min = find_with_hof(&tab, minimum_operator());
    match min {
        Some(val) => println!("The minimum value is {}", val),
        None => eprintln!("There is no minimum"),
    }
    //ANCHOR_END: min_usage

    //ANCHOR: max_variable
    let max_op: fn(i32, i32) -> i32 = |x, y| if x >= y { x } else { y };
    //ANCHOR_END: max_variable

    //ANCHOR: option_filter
    let max_val: Option<i32> = find_with_hof(&tab, max_op);
    let odd_max: Option<i32> = max_val.filter(|x| x % 2 == 1);
    match odd_max {
        Some(_) => println!("The maximum value is an odd number"),
        None => {
            if max_val.is_some() {
                println!("The maximum value is an even number")
            } else {
                eprintln!("There is no maximum")
            }
        }
    }
    //ANCHOR_END: option_filter

    //ANCHOR: option_map
    let two: f32 = 2.0f32;

    let sum: Option<i32> = find_with_hof(&tab, sum_operator());
    let half: Option<f32> = sum.map(|x: i32| (x as f32) / two);
    match half {
        Some(val) => println!("The sum of the elements divided by two is {}", val),
        None => eprintln!("There is no sum"),
    }
    //ANCHOR_END: option_map
}

src/binary_operator.rs

// ANCHOR: binary_operator
pub type BinaryOperator<T> = fn(T, T) -> T;
// ANCHOR_END: binary_operator

/// Returns a closure that computes the minimum
/// between two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{minimum_operator};
/// # fn main() {
/// let f = minimum_operator();
/// assert!(f(1,2) == 1);
/// # }
/// ```
// ANCHOR: minimum_operator
pub fn minimum_operator<T: PartialOrd>() -> BinaryOperator<T> {
    |x: T, y: T| if x <= y { x } else { y }
}
// ANCHOR_END: minimum_operator

/// Returns a closure that computes the maximum
/// between two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{maximum_operator};
/// # fn main() {
/// let f = maximum_operator();
/// assert!(f(1,2) == 2);
/// # }
/// ```
// ANCHOR: maximum_operator
pub fn maximum_operator<T: PartialOrd>() -> BinaryOperator<T> {
    |x: T, y: T| if x >= y { x } else { y }
}
// ANCHOR_END: maximum_operator

/// Returns a closure that computes the sum
/// of two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{sum_operator};
/// # fn main() {
/// let f = sum_operator();
/// assert!(f(1,2) == 3);
/// # }
/// ```
// ANCHOR: sum_operator
pub fn sum_operator<T: std::ops::Add<Output = T>>() -> BinaryOperator<T> {
    |x: T, y: T| x + y
}
// ANCHOR_END: sum_operator

/// Returns a closure that computes the product
/// of two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{mul_operator};
/// # fn main() {
/// let f = mul_operator();
/// assert!(f(1,2) == 2);
/// # }
/// ```
// ANCHOR: mul_operator
pub fn mul_operator<T: std::ops::Mul<Output = T>>() -> BinaryOperator<T> {
    |x: T, y: T| x * y
}
// ANCHOR_END: mul_operator

src/find.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::binary_operator::BinaryOperator;

/// Computes the result of a binary reduction of an Array of a type T.
/// Take the binary operation as a function.
/// Returns a [Option::Some] containing the result value
/// or [Option::None] if the array was empty.
///
/// # Example
///
/// ```
/// # use closures::find::{find_with_hof};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_with_hof(&tab,|x, y| if x <= y { x } else { y });
/// assert!(min == Some(2));
/// # }
/// ```
// ANCHOR: find_with_hof
pub fn find_with_hof<T: Copy>(tab: &[T], op: BinaryOperator<T>) -> Option<T> {
    let mut res = None;
    // Here, if T is Copyable, t is not moved in the loop
    for t in tab {
        if let Some(val) = res {
            res = Some(op(val, *t))
        } else {
            res = Some(*t)
        }
    }
    res
}
// ANCHOR_END: find_with_hof

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!("]");
}
}