Calling a generic function with different Primitive types

fizz_buzz is a generic function over T, which also return Fizzy struct with generic T. I don't know how different primitives can be converted to generic T and return Fizzy from fizzbuzz function.

pub struct Matcher<T> {

        pub output: String,
        pub closure: Box<dyn Fn(T) -> bool>,


    }

impl<T> Matcher<T> 
    {
    pub fn new<F, S>(_matcher: F, _subs: S) -> Matcher<T> 
     where F: Fn(T) -> bool + 'static,
            S: ToString {

        Self {
            closure: Box::new(_matcher),
            output: _subs.to_string(),
        }
    }
}

#[derive(Default)]
pub struct Fizzy<T> (Vec::<Matcher<T>>) ;

impl<T> Fizzy<T> 
    where T: Copy + Default + ToString, {
    pub fn new() -> Self {
        Fizzy(vec![])
    }

    pub fn add_matcher(self, _matcher: Matcher<T>) -> Self {
        let mut closures = self.0;
        closures.push(_matcher);
        Fizzy(closures)

    }

    pub fn apply<I>(self, iter: I) -> impl Iterator<Item = String> 
        where I : Iterator<Item = T>  {
        let res = iter.map(move |item| self.per_element(item));
        res
    }


    pub fn per_element(&self, item: T) -> String {
        let output = self.0
            .iter()
            .filter(|matcher| (matcher.closure)(item))
            .map(|matcher| matcher.output.clone())
            .collect::<String>();


        if output.is_empty() {
            item.to_string()
        } else {
            output
        }
    }
}


pub fn fizz_buzz<T>() -> Fizzy<T> {
    Fizzy::new()
            .add_matcher(Matcher::new(|n: i32| n % 5 == 0, "Buzz"))
            .add_matcher(Matcher::new(|n: i32| n % 3 == 0, "Fizz"))

}


macro_rules! expect {
    () => {
        vec![
            "1", "2", "fizz", "4", "buzz", "fizz", "7", "8", "fizz", "buzz", "11", "fizz", "13",
            "14", "fizzbuzz", "16",
        ]
    };
}

fn main(){

    let got = fizz_buzz::<u64>().apply(1_u64..=16).collect::<Vec<_>>();
    assert_eq!(expect!(), got);

    let got = fizz_buzz::<u8>().apply(1_u8..=16).collect::<Vec<_>>();
    assert_eq!(expect!(), got);

    let got = fizz_buzz::<i32>().apply(1..=16).collect::<Vec<_>>();
    assert_eq!(expect!(), got);

}

This is an exercise on Exercism :slight_smile:

This is how I solved it:

pub fn fizz_buzz<T>() -> Fizzy<T>
    where T: From<u8> + 'static + Copy + ToString + Rem<Output = T> + PartialEq
{
    let zero = 0.into();
    let three = 3.into();
    let five = 5.into();
    Fizzy::new()
        .add_matcher(Matcher::new(move |n| n % three == zero, "fizz"))
        .add_matcher(Matcher::new(move |n| n % five == zero, "buzz"))
}

The key thing to understand above is that all of Rust's integer types, with the sole exception of i8, can be converted to from a u8, hence the bound From<u8> on T in the where clause.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.