1#![forbid(unsafe_code)]
2#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct Dimensions {
21 width: u32,
22 height: u32,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum DimensionsError {
27 InvalidWidth,
28 InvalidHeight,
29}
30
31fn validate_dimensions(width: u32, height: u32) -> Result<(u32, u32), DimensionsError> {
32 if width == 0 {
33 return Err(DimensionsError::InvalidWidth);
34 }
35
36 if height == 0 {
37 return Err(DimensionsError::InvalidHeight);
38 }
39
40 Ok((width, height))
41}
42
43impl Dimensions {
44 pub fn new(width: u32, height: u32) -> Result<Self, DimensionsError> {
45 let (width, height) = validate_dimensions(width, height)?;
46 Ok(Self { width, height })
47 }
48
49 #[must_use]
50 pub fn width(&self) -> u32 {
51 self.width
52 }
53
54 #[must_use]
55 pub fn height(&self) -> u32 {
56 self.height
57 }
58
59 #[must_use]
60 pub fn area(&self) -> u64 {
61 u64::from(self.width) * u64::from(self.height)
62 }
63
64 #[must_use]
65 pub fn is_landscape(&self) -> bool {
66 self.width > self.height
67 }
68
69 #[must_use]
70 pub fn is_portrait(&self) -> bool {
71 self.height > self.width
72 }
73
74 #[must_use]
75 pub fn is_square(&self) -> bool {
76 self.width == self.height
77 }
78}
79
80pub fn pixel_area(width: u32, height: u32) -> Result<u64, DimensionsError> {
81 Ok(Dimensions::new(width, height)?.area())
82}
83
84pub fn is_landscape(width: u32, height: u32) -> Result<bool, DimensionsError> {
85 Ok(Dimensions::new(width, height)?.is_landscape())
86}
87
88pub fn is_portrait(width: u32, height: u32) -> Result<bool, DimensionsError> {
89 Ok(Dimensions::new(width, height)?.is_portrait())
90}
91
92pub fn is_square(width: u32, height: u32) -> Result<bool, DimensionsError> {
93 Ok(Dimensions::new(width, height)?.is_square())
94}
95
96#[cfg(test)]
97mod tests {
98 use super::{Dimensions, DimensionsError, is_landscape, is_portrait, is_square, pixel_area};
99
100 #[test]
101 fn validates_dimensions_and_area() {
102 let dimensions = Dimensions::new(1920, 1080).unwrap();
103
104 assert_eq!(dimensions.width(), 1920);
105 assert_eq!(dimensions.height(), 1080);
106 assert_eq!(dimensions.area(), 2_073_600);
107 assert!(dimensions.is_landscape());
108 assert!(!dimensions.is_portrait());
109 assert!(!dimensions.is_square());
110 assert_eq!(pixel_area(1920, 1080).unwrap(), 2_073_600);
111 assert!(is_landscape(1920, 1080).unwrap());
112 }
113
114 #[test]
115 fn detects_portrait_and_square_sizes() {
116 assert!(is_portrait(1080, 1920).unwrap());
117 assert!(is_square(512, 512).unwrap());
118 assert!(!is_square(640, 480).unwrap());
119 }
120
121 #[test]
122 fn rejects_invalid_dimensions() {
123 assert_eq!(Dimensions::new(0, 1080), Err(DimensionsError::InvalidWidth));
124 assert_eq!(
125 Dimensions::new(1920, 0),
126 Err(DimensionsError::InvalidHeight)
127 );
128 assert_eq!(pixel_area(0, 1), Err(DimensionsError::InvalidWidth));
129 }
130}