1extern crate ansi_term;
15
16use std::f64::consts::PI;
17use std::io::{self, Stdout, Write};
18
19use ansi_term::Color;
20
21pub struct Colors<W> {
47 wrapped: W,
48 spread: f64,
49 frequency: f64,
50 seed: f64,
51}
52
53pub fn stdout() -> Colors<Stdout> {
55 Colors::new(io::stdout())
56}
57
58impl<W> Colors<W> {
59 pub fn new(wrapped: W) -> Self {
62 Self::configure(wrapped, 3.0, 0.1, 0.0)
63 }
64
65 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 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}