1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::io::prelude::*;
use std::fmt::{Display, Formatter, Result};
use Value::*;

/// A FizzBuzz value.
///
/// Unsigned integers can be converted to FizzBuzz values.
///
/// # Examples
/// ```
/// use fizzbuzz::Value::*;
///
/// let mut iter = (1..).map(fizzbuzz::Value::from);
///
/// assert_eq!(iter.next(), Some(Number(1)));
/// assert_eq!(iter.next(), Some(Number(2)));
/// assert_eq!(iter.next(), Some(Fizz));
/// assert_eq!(iter.next(), Some(Number(4)));
/// assert_eq!(iter.next(), Some(Buzz));
/// assert_eq!(iter.next(), Some(Fizz));
/// assert_eq!(iter.next(), Some(Number(7)));
/// ```
#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
pub enum Value {
    Fizz,
    Buzz,
    FizzBuzz,
    Number(u32),
}

impl From<u32> for Value {
    fn from(n: u32) -> Value {
        match (n % 3, n % 5) {
            (0, 0) => FizzBuzz,
            (0, _) => Fizz,
            (_, 0) => Buzz,
            (_, _) => Number(n),
        }
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter) -> Result {
        match *self {
            Fizz => write!(f, "Fizz"),
            Buzz => write!(f, "Buzz"),
            FizzBuzz => write!(f, "FizzBuzz"),
            Number(n) => write!(f, "{}", n),
        }
    }
}

/// Prints FizzBuzz values over the specified sequence to the standard output.
///
/// # Examples
/// ```
/// fizzbuzz::fizzbuzz(1..100);
///
/// // 1
/// // 2
/// // Fizz
/// // 4
/// // Buzz
/// // Fizz
/// // 7
/// // <...>
/// ```
///
/// # Panics
///
/// Panics on `stdout` output error.
pub fn fizzbuzz<I>(it: I)
where
    I: Iterator<Item = u32>,
{
    let stdout = std::io::stdout();
    let mut stdout = stdout.lock();

    for n in it {
        writeln!(stdout, "{}", Value::from(n)).expect("Failed to output");
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let expected = [
            FizzBuzz,
            Number(1),
            Number(2),
            Fizz,
            Number(4),
            Buzz,
            Fizz,
            Number(7),
            Number(8),
            Fizz,
            Buzz,
            Number(11),
            Fizz,
            Number(13),
            Number(14),
            FizzBuzz,
            Number(16),
            Number(17),
            Fizz,
            Number(19),
        ];

        for (i, &exp) in expected.iter().enumerate() {
            assert_eq!(Value::from(i as u32), exp);
        }
    }
}