Fizzbuzz in Rust / src / lib.rs

//! 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
}