gen_types_composes

src/main.rs

/* ANCHOR: all */

/// In gen_types_composes we introduce genericity through traits and in particular, [Copy],
/// [Clone], [std::fmt::Display] .
// ANCHOR: something_or_nothing
enum SomethingOrNothing<T> {
    Nothing,
    Something(T),
}
// ANCHOR_END: something_or_nothing

// ANCHOR: new
impl<T> SomethingOrNothing<T> {
    fn new(val: T) -> SomethingOrNothing<T> {
        SomethingOrNothing::Something(val)
    }
}
// ANCHOR_END: new

// ANCHOR: print
// Print function
// We know the generic type T must be Displayable
fn print<T: std::fmt::Display>(val: SomethingOrNothing<T>) {
    match val {
        SomethingOrNothing::Nothing => println!("Nothing."),
        SomethingOrNothing::Something(val) => println!("Something is: {}", val),
    }
}
// ANCHOR_END: print

// ANCHOR: clone
impl<T: Clone> Clone for SomethingOrNothing<T> {
    fn clone(&self) -> Self {
        match self {
            SomethingOrNothing::Nothing => SomethingOrNothing::Nothing,
            SomethingOrNothing::Something(val) => SomethingOrNothing::new(val.clone()),
        }
    }
}
// ANCHOR_END: clone

// ANCHOR: copy
impl<T: Copy> Copy for SomethingOrNothing<T> {}
// ANCHOR_END: copy

// If we remove Copy, we have a problem with the t in tab
// in the computation of the minimum.
// ANCHOR: minimum
trait Minimum: Copy {
    fn min(self, rhs: Self) -> Self;
}
// ANCHOR_END: minimum

// ANCHOR: minimum_impl
impl<T: Minimum> Minimum for SomethingOrNothing<T> {
    fn min(self, rhs: Self) -> Self {
        match (self, rhs) {
            (SomethingOrNothing::Nothing, SomethingOrNothing::Nothing) => {
                SomethingOrNothing::Nothing
            }
            (SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
                SomethingOrNothing::new(lhs.min(rhs))
            }
            (SomethingOrNothing::Nothing, SomethingOrNothing::Something(rhs)) => {
                SomethingOrNothing::new(rhs)
            }
            (SomethingOrNothing::Something(lhs), SomethingOrNothing::Nothing) => {
                SomethingOrNothing::new(lhs)
            }
        }
    }
}
// ANCHOR_END: minimum_impl

// i32 is Copy, like other primitive types (f32, f64, etc.).
// Fixed-size arrays [T; N] are also Copy when T is Copy.
// ANCHOR: minimum_i32
impl Minimum for i32 {
    fn min(self, rhs: Self) -> Self {
        if self < rhs { self } else { rhs }
    }
}
// ANCHOR_END: minimum_i32

const SIZE: usize = 9;

fn read_command_line() -> [i32; SIZE] {
    [10, 32, 12, 43, 52, 53, 83, 2, 9]
}

// Prints tab and returns tab.
// Tab would be destructed at the end of the function otherwise.
// ANCHOR: print_tab
fn print_tab<T: std::fmt::Display>(tab: [T; SIZE]) {
    for t in tab {
        print!("{} ", t);
    }
    println!();
}
// ANCHOR_END: print_tab

// ANCHOR: find_min
fn find_min<T: Minimum>(tab: [T; SIZE]) -> SomethingOrNothing<T> {
    let mut current_minimum = SomethingOrNothing::Nothing;
    // Here, if T is not Copyable, tab is consumed and cannot be returned
    for t in tab {
        current_minimum = current_minimum.min(SomethingOrNothing::new(t));
    }
    current_minimum
}
// ANCHOR_END: find_min

// ANCHOR: main
fn main() {
    let tab = read_command_line();
    println!("Among the Somethings in the list:");
    print_tab(tab);
    let min = find_min(tab);
    print(min);
}
// ANCHOR_END: main

/* ANCHOR_END: all */