//! The `fizzbuzz` crate provides the way to get a customizable fizzbuzz implementation
//!
//! # Examples
//!
//! ```
//! let mut acc = "".to_string();
//! for i in 1..16 {
//! acc = acc + &*fizzbuzz::cowbuzz(&[
//! ("Fizz", &|i: i32| i % 3 == 0),
//! ("Buzz", &|i: i32| i % 5 == 0),
//! ], i) + " ";
//! }
//!
//! assert_eq!(acc, "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz ".to_string());
//! ```
#![feature(conservative_impl_trait)]
extern crate monoid;
extern crate itertools;
extern crate tool;
use itertools::Itertools;
use monoid::Monoid;
use tool::prelude::*;
use std::borrow::Cow;
use std::convert::Into;
///takes a tuple of strings and conditions
///shows the numbers if conditions are false
pub fn fizzbuzz<'a>(tuples: &[(&'a str, &Fn(i32) -> bool)], i: i32) -> String {
accumulate(tuples, i)
}
///takes a tuple of strings and conditions
///shows the numbers if conditions are false
///faster than using a String
pub fn cowbuzz<'a>(tuples: &[(&'a str, &Fn(i32) -> bool)], i: i32) -> Cow<'a, str> {
accumulate(tuples, i)
}
//does the monoid operation on the slice of tuples if the closure evaluates to true
fn accumulate<'a, T: Monoid>(tuples: &[(&'a str, &Fn(i32) -> bool)], i: i32) -> T
where T: From<&'a str> + From<String> {
tuples.iter()
.filter(apply(second, i))
.map(first)
.cloned()
.map(<&str>::into)
.fold1(T::op)
.unwrap_or_else(|| i.to_string().into())
//op just concatenates, but String does not satisfy Add
}
fn apply<A, B, C, F, G>(mut f: F, a: A)
-> impl FnMut(&B) -> C // must still be `for<'r> impl FnMut(&'r B) -> C`, because that’s what filter requires
where F: FnMut(B) -> G, // must not be `for<'r> FnMut(&'r B) -> G`, because regular functions do not implement it
G: FnMut(A) -> C,
B: Copy, // for dereferencing
A: Clone {
move |b| f(*b)(a.clone()) // this must do any bridging necessary to satisfy the requirements
}