diff --git a/src/config.rs b/src/config.rs index 1ac93ec..df1a16e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ -use crate::constants::{UNIT_LENGTH, UNIT_SIZE, WINDOW_TITLE}; +use crate::constants::WINDOW_TITLE; use crate::validator; +use crate::window_size::WindowSize; pub struct Title(String); @@ -14,63 +15,36 @@ impl Title { } } -pub struct Width(u32); - -impl Width { - pub fn new(width: u32) -> Result { - validator::validate_numeric_range(width, 1, 1000)?; - Ok(Self(width)) - } - - pub fn value(&self) -> u32 { - self.0 - } -} - -pub struct Height(u32); - -impl Height { - pub fn new(height: u32) -> Result { - validator::validate_numeric_range(height, 1, 1000)?; - Ok(Self(height)) - } - - pub fn value(&self) -> u32 { - self.0 - } -} - pub struct WindowConfig { - pub title: Title, - pub width: Width, - pub height: Height, + title: Title, + window_size: WindowSize, } impl WindowConfig { - pub fn new(title: &str, width: u32, height: u32) -> Result { - Ok(Self { - title: Title::new(title)?, - width: Width::new(width)?, - height: Height::new(height)?, - }) + pub fn new() -> Self { + let title = Title::new(WINDOW_TITLE).unwrap(); + let window_size = WindowSize::new_by_unit_size(); + + Self { title, window_size } } - fn calculate_window_size() -> (u32, u32) { - (UNIT_SIZE.0 * UNIT_LENGTH.0, UNIT_SIZE.1 * UNIT_LENGTH.1) + pub fn title(&self) -> &str { + self.title.value() } - fn create_with_default_size(title: &str) -> Result { - let (width, height) = Self::calculate_window_size(); - Self::new(title, width, height) + pub fn width(&self) -> u32 { + self.window_size.width().value() } -} -pub fn create_window_config() -> Result { - WindowConfig::create_with_default_size(WINDOW_TITLE) + pub fn height(&self) -> u32 { + self.window_size.height().value() + } } #[cfg(test)] mod tests { + use crate::constants::{UNIT_LENGTH, UNIT_SIZE}; + use super::*; use rstest::rstest; @@ -86,61 +60,12 @@ mod tests { assert!(Title::new(title).is_ok()); } - #[rstest] - #[case::min_1(1)] - #[case::max_1000(1000)] - #[case::normal(50)] - #[should_panic] - #[case::min_0(0)] - #[should_panic] - #[case::max_1001(1001)] - fn test_width_new(#[case] width: u32) { - assert!(Width::new(width).is_ok()); - } - - #[rstest] - #[case::min_1(1)] - #[case::max_1000(1000)] - #[case::normal(50)] - #[should_panic] - #[case::min_0(0)] - #[should_panic] - #[case::max_1001(1001)] - fn test_height_new(#[case] height: u32) { - assert!(Height::new(height).is_ok()); - } - - #[rstest] - #[case::normal("Test Window", 800, 600)] - #[case::min_1("T", 1, 1)] - #[case::max_1000("12345678901234567890123456789012345678901234567890", 1000, 1000)] - #[should_panic] - #[case::panic_title("", 1, 1)] - #[should_panic] - #[case::panic_width("T", 0, 1)] - #[should_panic] - #[case::panic_height("T", 1, 0)] - fn test_window_config_creation(#[case] title: &str, #[case] width: u32, #[case] height: u32) { - let window_config = WindowConfig::new(title, width, height).unwrap(); - - assert_eq!(window_config.title.value(), title); - assert_eq!(window_config.width.value(), width); - assert_eq!(window_config.height.value(), height); - } - #[test] - fn test_default_window_size() { - let window_config = WindowConfig::create_with_default_size("Default Size Window").unwrap(); - let expected_size = WindowConfig::calculate_window_size(); - - assert_eq!( - (window_config.width.value(), window_config.height.value()), - expected_size - ); - } + fn test_window_config_new() { + let window_config = WindowConfig::new(); - #[test] - fn test_create_window_config() { - create_window_config().unwrap(); + assert_eq!(window_config.title(), WINDOW_TITLE); + assert_eq!(window_config.width(), UNIT_SIZE.0 * UNIT_LENGTH.0); + assert_eq!(window_config.height(), UNIT_SIZE.1 * UNIT_LENGTH.1); } } diff --git a/src/lib.rs b/src/lib.rs index 53f1667..8d21a41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ mod text_resources; mod utils; mod validator; mod window; +mod window_size; use my_app::MyApp; diff --git a/src/position.rs b/src/position.rs index dfd0479..bc9b714 100644 --- a/src/position.rs +++ b/src/position.rs @@ -1,20 +1,48 @@ use bevy::prelude::*; -use crate::{game_timer::GameTimer, utils}; +use crate::{constants::UNIT_LENGTH, game_timer::GameTimer, utils, validator}; -#[derive(Component)] -pub struct Position { - x: i32, - y: i32, +struct PosX(i32); + +impl PosX { + fn new(x: i32) -> Result { + validator::validate_numeric_range(x, 0, (UNIT_LENGTH.0 - 1) as i32)?; + + Ok(Self(x)) + } + + pub fn value(&self) -> i32 { + self.0 + } +} + +struct PosY(i32); + +impl PosY { + fn new(y: i32) -> Result { + validator::validate_numeric_range(y, 0, (UNIT_LENGTH.1 - 1) as i32)?; + + Ok(Self(y)) + } + + pub fn value(&self) -> i32 { + self.0 + } } +#[derive(Component)] +pub struct Position(PosX, PosY); + impl Position { - pub fn new(x: i32, y: i32) -> Self { - Self { x, y } + pub fn new(x: i32, y: i32) -> Result { + let pos_x = PosX::new(x)?; + let pos_y = PosY::new(y)?; + + Ok(Self(pos_x, pos_y)) } pub fn vec2(&self) -> Vec2 { - Vec2::new(self.x as f32, self.y as f32) + Vec2::new(self.x() as f32, self.y() as f32) } pub fn translation(&self, origin: Vec2) -> Vec3 { @@ -30,9 +58,17 @@ impl Position { } for mut position in position_query.iter_mut() { - position.y -= 1; + *position = Position::new(position.x(), position.y() - 1).unwrap(); } } + + pub fn x(&self) -> i32 { + self.0.value() + } + + pub fn y(&self) -> i32 { + self.1.value() + } } #[cfg(test)] @@ -43,26 +79,26 @@ mod tests { #[test] fn test_position_new() { - let position = Position::new(10, 20); - assert_eq!(position.x, 10); - assert_eq!(position.y, 20); + let position = Position::new(5, 1).unwrap(); + assert_eq!(position.x(), 5); + assert_eq!(position.y(), 1); } #[test] fn test_position_vec2() { - let position: Position = Position::new(10, 20); + let position: Position = Position::new(4, 9).unwrap(); let vec2 = position.vec2(); - assert_eq!(vec2, Vec2::new(10.0, 20.0)); + assert_eq!(vec2, Vec2::new(4.0, 9.0)); } #[test] fn test_position_translation() { - let position = Position::new(10, 20); + let position = Position::new(3, 8).unwrap(); let origin = Vec2::new(-100.0, 5.0); let translation = position.translation(origin); - let expected_x = unit_size().x * position.x as f32 + origin.x; - let expected_y = unit_size().y * position.y as f32 + origin.y; + let expected_x = unit_size().x * position.x() as f32 + origin.x; + let expected_y = unit_size().y * position.y() as f32 + origin.y; let expected_translation = Vec3::new(expected_x, expected_y, 0.0); assert_eq!(translation, expected_translation); diff --git a/src/sprite.rs b/src/sprite.rs index 4f997ec..6b0f25b 100644 --- a/src/sprite.rs +++ b/src/sprite.rs @@ -40,7 +40,7 @@ pub fn spawn_block(commands: &mut Commands, block_patterns: &mut Res Vec2 { - Vec2::new(tuple.0 as f32, tuple.1 as f32) +pub fn vec2_from_tuple + Copy>(tuple: (T, T)) -> Vec2 { + Vec2::new(tuple.0.into(), tuple.1.into()) } pub fn unit_size() -> Vec2 { - vec2_from_tuple(constants::UNIT_SIZE) + vec2_from_tuple((UNIT_SIZE.0 as u16, UNIT_SIZE.1 as u16)) } #[cfg(test)] @@ -18,7 +18,7 @@ mod tests { #[rstest] #[case::tuple((100, 50), Vec2::new(100.0, 50.0))] #[case::tuple((200, 100), Vec2::new(200.0, 100.0))] - fn test_vec2_from_tuple(#[case] tuple: (u32, u32), #[case] expected: Vec2) { + fn test_vec2_from_tuple(#[case] tuple: (u8, u8), #[case] expected: Vec2) { let actual = vec2_from_tuple(tuple); assert_eq!(actual, expected); } @@ -26,6 +26,9 @@ mod tests { #[test] fn test_unit_size() { let actual = unit_size(); - assert_eq!(actual, vec2_from_tuple(constants::UNIT_SIZE)); + assert_eq!( + actual, + vec2_from_tuple((UNIT_SIZE.0 as u16, UNIT_SIZE.1 as u16)) + ); } } diff --git a/src/validator.rs b/src/validator.rs index 7a02e15..558b611 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -11,7 +11,11 @@ pub fn validate_string_length(value: &str, min: usize, max: usize) -> Result<(), } } -pub fn validate_numeric_range(value: u32, min: u32, max: u32) -> Result<(), String> { +pub fn validate_numeric_range( + value: T, + min: T, + max: T, +) -> Result<(), String> { if (min..=max).contains(&value) { Ok(()) } else { diff --git a/src/window.rs b/src/window.rs index 96fd67b..f10ef5b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,6 +1,6 @@ use bevy::prelude::*; -use crate::{config, utils::unit_size}; +use crate::{config::WindowConfig, utils::unit_size}; fn create_window(title: &str, width: u32, height: u32) -> Window { Window { @@ -11,12 +11,12 @@ fn create_window(title: &str, width: u32, height: u32) -> Window { } pub fn init_window() -> Window { - let window_config = config::create_window_config().unwrap(); + let window_config = WindowConfig::new(); create_window( - window_config.title.value(), - window_config.width.value(), - window_config.height.value(), + window_config.title(), + window_config.width(), + window_config.height(), ) } diff --git a/src/window_size.rs b/src/window_size.rs new file mode 100644 index 0000000..4b35bc7 --- /dev/null +++ b/src/window_size.rs @@ -0,0 +1,95 @@ +use crate::{ + constants::{UNIT_LENGTH, UNIT_SIZE}, + validator, +}; + +pub struct Width(u32); + +impl Width { + pub fn new(width: u32) -> Result { + validator::validate_numeric_range(width, 1, 1000)?; + Ok(Self(width)) + } + + pub fn new_by_unit() -> Result { + Width::new(UNIT_SIZE.0 * UNIT_LENGTH.0) + } + + pub fn value(&self) -> u32 { + self.0 + } +} + +pub struct Height(u32); + +impl Height { + pub fn new(height: u32) -> Result { + validator::validate_numeric_range(height, 1, 1000)?; + Ok(Self(height)) + } + + pub fn new_by_unit() -> Result { + Height::new(UNIT_SIZE.1 * UNIT_LENGTH.1) + } + + pub fn value(&self) -> u32 { + self.0 + } +} + +pub struct WindowSize(Width, Height); + +impl WindowSize { + pub fn new_by_unit_size() -> Self { + let width = Width::new_by_unit().unwrap(); + let height = Height::new_by_unit().unwrap(); + + Self(width, height) + } + + pub fn width(&self) -> &Width { + &self.0 + } + + pub fn height(&self) -> &Height { + &self.1 + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rstest::rstest; + + #[rstest] + #[case::min_1(1)] + #[case::max_1000(1000)] + #[case::normal(50)] + #[should_panic] + #[case::min_0(0)] + #[should_panic] + #[case::max_1001(1001)] + fn test_width_new(#[case] width: u32) { + assert!(Width::new(width).is_ok()); + } + + #[rstest] + #[case::min_1(1)] + #[case::max_1000(1000)] + #[case::normal(50)] + #[should_panic] + #[case::min_0(0)] + #[should_panic] + #[case::max_1001(1001)] + fn test_height_new(#[case] height: u32) { + assert!(Height::new(height).is_ok()); + } + + #[test] + fn test_new_by_unit_size() { + let window_size = WindowSize::new_by_unit_size(); + + assert_eq!(window_size.width().value(), UNIT_SIZE.0 * UNIT_LENGTH.0); + assert_eq!(window_size.height().value(), UNIT_SIZE.1 * UNIT_LENGTH.1); + } +}