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