rainbowcoat/
lib.rs

1//! Colors writable type characters with the ascii rainbow
2//!
3//! You can use this any type that requires a `io::Write` type
4//!
5//! # examples
6//!
7//! ```rust
8//! use std::io::Write;
9//! write!(
10//!   &mut rainbowcoat::stdout(),
11//!   "hello rainbow"
12//! );
13//! ```
14extern crate  ansi_term;
15
16use std::f64::consts::PI;
17use std::io::{self, Stdout, Write};
18
19use ansi_term::Color;
20
21/// Colors writable type characters with the ascii rainbow
22///
23/// You can use this any type that requires a `io::Write` type
24///
25/// # examples
26///
27/// Write direcly to stdout
28///
29/// ```rust
30/// use std::io::{self, Write};
31/// write!(
32///   &mut rainbowcoat::Colors::new(io::stdout()),
33///   "hello rainbow"
34/// );
35/// ```
36///
37/// A convenience function makes this common case even easier
38///
39/// ```rust
40/// use std::io::Write;
41/// write!(
42///   &mut rainbowcoat::stdout(),
43///   "hello rainbow"
44/// );
45/// ```
46pub struct Colors<W> {
47    wrapped: W,
48    spread: f64,
49    frequency: f64,
50    seed: f64,
51}
52
53/// Convenience function that wraps `std::io::Stdout` in a`Colors` instance
54pub fn stdout() -> Colors<Stdout> {
55    Colors::new(io::stdout())
56}
57
58impl<W> Colors<W> {
59    /// Creates a new `Colors` instance with default spread of `3.0`,
60    /// frequency of `0.1` and seed valud of `0.0`
61    pub fn new(wrapped: W) -> Self {
62        Self::configure(wrapped, 3.0, 0.1, 0.0)
63    }
64
65    /// Creates a more configurable instance with provided params
66    pub fn configure(wrapped: W, spread: f64, frequency: f64, seed: f64) -> Self {
67        Self {
68            wrapped,
69            spread,
70            frequency,
71            seed,
72        }
73    }
74
75    fn color(&mut self, seed: f64) -> Color {
76        let i = self.frequency * seed / self.spread;
77        let red = i.sin() * 127.00 + 128.00;
78        let green = (i + (PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
79        let blue = (i + (PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;
80        Color::RGB(red as u8, green as u8, blue as u8)
81    }
82}
83
84impl<W: Write> Write for Colors<W> {
85    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
86        for line in ::std::str::from_utf8(buf).unwrap().lines() {
87            let mut seed = self.seed;
88            for c in line.chars() {
89                seed += 1.0;
90                // fixme: Color#paint doesn't work with scalar char types
91                let mut s = String::with_capacity(1);
92                s.push(c);
93                let color = self.color(seed);
94                write!(&mut self.wrapped, "{}", color.paint(s))?
95            }
96            write!(&mut self.wrapped, "\n")?;
97        }
98        Ok(buf.len())
99    }
100    fn flush(&mut self) -> io::Result<()> {
101        self.wrapped.flush()
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::{stdout, Colors};
108    use ansi_term::Color;
109    use std::io::{self, Write};
110
111    #[test]
112    fn colors_colors() {
113        assert_eq!(Colors::new(io::sink()).color(0.0), Color::RGB(128, 237, 18))
114    }
115
116    #[test]
117    fn colors_writes() {
118        assert!(write!(&mut Colors::new(Vec::new()), "hello").is_ok());
119    }
120
121    #[test]
122    fn stdout_convenience() {
123        assert!(write!(&mut stdout(), "hello").is_ok());
124    }
125}