diff --git a/src/main.rs b/src/main.rs index c6314e7..10a4973 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ pub mod error; -mod pattern; +pub mod pattern; pub mod printer; +pub mod sampler; pub mod term; mod vec; diff --git a/src/sampler/char.rs b/src/sampler/char.rs new file mode 100644 index 0000000..d577d56 --- /dev/null +++ b/src/sampler/char.rs @@ -0,0 +1,61 @@ +pub trait CharConverter { + fn convert(&self, level: f32) -> char; +} + +pub struct CharConverterImpl { + chars: String, +} + +impl CharConverterImpl { + pub fn new(chars: String) -> Self { + Self { chars } + } +} + +impl CharConverter for CharConverterImpl { + fn convert(&self, level: f32) -> char { + assert!(level >= 0.0); + assert!(level < 1.0); + + let index = (level * self.chars.len() as f32) as usize; + + self.chars.chars().nth(index).unwrap() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + #[should_panic] + fn convert_index_below_zero() { + CharConverterImpl::new("abc".to_string()).convert(-0.1); + } + + #[test] + fn convert_index_zero() { + let converter = CharConverterImpl::new("abc".to_string()); + + assert_eq!('a', converter.convert(0.0)); + } + + #[test] + fn convert() { + let converter = CharConverterImpl::new("abc".to_string()); + + assert_eq!('b', converter.convert(0.5)); + } + + #[test] + #[should_panic] + fn convert_index_one() { + CharConverterImpl::new("abc".to_string()).convert(1.0); + } + + #[test] + #[should_panic] + fn convert_index_above_one() { + CharConverterImpl::new("abc".to_string()).convert(1.1); + } +} diff --git a/src/sampler/color.rs b/src/sampler/color.rs new file mode 100644 index 0000000..692cd73 --- /dev/null +++ b/src/sampler/color.rs @@ -0,0 +1,64 @@ +use crossterm::style::Color; + +pub trait ColorConverter { + fn convert(&self, level: f32) -> Color; +} + +pub struct ColorConverterImpl { + colors: Vec, +} + +impl ColorConverterImpl { + pub fn new(colors: Vec) -> Self { + Self { colors } + } +} + +impl ColorConverter for ColorConverterImpl { + fn convert(&self, level: f32) -> Color { + assert!(level >= 0.0); + assert!(level < 1.0); + + let index = (level * self.colors.len() as f32) as usize; + + self.colors[index] + } +} + +#[cfg(test)] +mod test { + use super::*; + use crossterm::style::Color::*; + + #[test] + #[should_panic] + fn convert_index_below_zero() { + ColorConverterImpl::new(vec![Red, Green, Blue]).convert(-0.1); + } + + #[test] + fn convert_index_zero() { + let converter = ColorConverterImpl::new(vec![Red, Green, Blue]); + + assert!(matches!(converter.convert(0.0), Red)); + } + + #[test] + fn convert() { + let converter = ColorConverterImpl::new(vec![Red, Green, Blue]); + + assert!(matches!(converter.convert(0.5), Green)); + } + + #[test] + #[should_panic] + fn convert_index_one() { + ColorConverterImpl::new(vec![Red, Green, Blue]).convert(1.0); + } + + #[test] + #[should_panic] + fn convert_index_above_one() { + ColorConverterImpl::new(vec![Red, Green, Blue]).convert(1.1); + } +} diff --git a/src/sampler/level.rs b/src/sampler/level.rs new file mode 100644 index 0000000..d833903 --- /dev/null +++ b/src/sampler/level.rs @@ -0,0 +1,65 @@ +pub enum Level { + Keep, + Draw(f32), + Clear, +} + +pub trait LevelConverter { + fn convert(&self, level: f32) -> Level; +} + +#[derive(Default)] +pub struct LevelConverterImpl; + +impl LevelConverter for LevelConverterImpl { + fn convert(&self, level: f32) -> Level { + if level < 0.0 { + Level::Keep + } else if level < 1.0 { + Level::Draw(level) + } else { + Level::Clear + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn convert_keep() { + let converter = LevelConverterImpl::default(); + + assert!(matches!(converter.convert(-0.1), Level::Keep)); + } + + #[test] + fn convert_draw() { + let converter = LevelConverterImpl::default(); + + if let Level::Draw(level) = converter.convert(0.0) { + assert_eq!(0.0, level); + } else { + panic!(); + } + if let Level::Draw(level) = converter.convert(0.5) { + assert_eq!(0.5, level); + } else { + panic!(); + } + if let Level::Draw(level) = converter.convert(0.9) { + assert_eq!(0.9, level); + } else { + panic!(); + } + } + + #[test] + fn convert_clear() { + let converter = LevelConverterImpl::default(); + + assert!(matches!(converter.convert(1.0), Level::Clear)); + assert!(matches!(converter.convert(1.5), Level::Clear)); + } +} diff --git a/src/sampler/mod.rs b/src/sampler/mod.rs new file mode 100644 index 0000000..a521828 --- /dev/null +++ b/src/sampler/mod.rs @@ -0,0 +1,3 @@ +mod color; +mod level; +mod char;