use std::{fmt::Debug,
ops::{Add, AddAssign, Sub, SubAssign}};
use crate::{ChUnit, ColWidth, RowHeight};
pub type Width = ColWidth;
pub type Height = RowHeight;
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
pub struct Size {
pub col_width: ColWidth,
pub row_height: RowHeight,
}
pub fn size(arg_size: impl Into<Size>) -> Size { arg_size.into() }
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Ord, Eq, Hash)]
pub enum SufficientSize {
IsLargeEnough,
IsTooSmall,
}
mod constructor {
use super::{Add, ColWidth, RowHeight, Size};
impl Size {
pub fn new(arg_dim: impl Into<Size>) -> Self { arg_dim.into() }
}
impl From<(ColWidth, RowHeight)> for Size {
fn from((width, height): (ColWidth, RowHeight)) -> Self {
Size {
col_width: width,
row_height: height,
}
}
}
impl From<(RowHeight, ColWidth)> for Size {
fn from((height, width): (RowHeight, ColWidth)) -> Self {
Size {
col_width: width,
row_height: height,
}
}
}
impl Add<RowHeight> for ColWidth {
type Output = Size;
fn add(self, rhs: RowHeight) -> Self::Output {
Size {
col_width: self,
row_height: rhs,
}
}
}
impl Add<ColWidth> for RowHeight {
type Output = Size;
fn add(self, rhs: ColWidth) -> Self::Output {
Size {
col_width: rhs,
row_height: self,
}
}
}
}
mod convert {
use super::{ColWidth, RowHeight, Size};
impl From<Size> for ColWidth {
fn from(size: Size) -> Self { size.col_width }
}
impl From<Size> for RowHeight {
fn from(size: Size) -> Self { size.row_height }
}
}
mod api {
use super::{Size, SufficientSize};
impl Size {
pub fn fits_min_size(&self, arg_min_size: impl Into<Size>) -> SufficientSize {
let size: Size = arg_min_size.into();
let min_width = size.col_width;
let min_height = size.row_height;
if self.col_width < min_width || self.row_height < min_height {
SufficientSize::IsTooSmall
} else {
SufficientSize::IsLargeEnough
}
}
}
}
mod debug {
use super::{Debug, Size};
impl Debug for Size {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[w: {w:?}, h: {h:?}]",
w = *self.col_width,
h = *self.row_height
)
}
}
}
mod ops {
use super::{Add, AddAssign, ChUnit, Size, Sub, SubAssign};
impl Sub<Size> for Size {
type Output = Size;
fn sub(self, rhs: Size) -> Self::Output {
let mut self_copy = self;
*self_copy.col_width -= *rhs.col_width;
*self_copy.row_height -= *rhs.row_height;
self_copy
}
}
impl Add<Size> for Size {
type Output = Size;
fn add(self, rhs: Size) -> Self::Output {
let mut self_copy = self;
*self_copy.col_width += *rhs.col_width;
*self_copy.row_height += *rhs.row_height;
self_copy
}
}
impl SubAssign<ChUnit> for Size {
fn sub_assign(&mut self, other: ChUnit) {
*self.col_width -= other;
*self.row_height -= other;
}
}
impl Sub<ChUnit> for Size {
type Output = Size;
fn sub(self, other: ChUnit) -> Self::Output {
let mut self_copy = self;
self_copy -= other;
self_copy
}
}
impl AddAssign<ChUnit> for Size {
fn add_assign(&mut self, other: ChUnit) {
*self.col_width += other;
*self.row_height += other;
}
}
impl Add<ChUnit> for Size {
type Output = Size;
fn add(self, other: ChUnit) -> Self::Output {
let mut self_copy = self;
self_copy += other;
self_copy
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{ch, height, width};
#[test]
fn test_dim() {
let size_1 = size(width(5) + height(10));
assert_eq!(size_1.col_width, ColWidth(ch(5)));
assert_eq!(*size_1.col_width, ch(5));
assert_eq!(size_1.row_height, RowHeight(ch(10)));
assert_eq!(*size_1.row_height, ch(10));
let size_2 = size(height(10) + width(5));
assert!(matches!(size_2.col_width, ColWidth(_)));
assert!(matches!(size_2.row_height, RowHeight(_)));
}
#[test]
fn test_size_new() {
let size = Size::new((ColWidth::new(5), RowHeight::new(10)));
assert_eq!(size.col_width, ColWidth(ch(5)));
assert_eq!(*size.col_width, 5.into());
assert_eq!(size.row_height, RowHeight(10.into()));
assert_eq!(*size.row_height, ch(10));
let size_2 = Size::new((width(5), height(10)));
assert!(matches!(size_2.col_width, ColWidth(_)));
assert!(matches!(size_2.row_height, RowHeight(_)));
}
#[test]
fn test_size_from() {
let size: Size = (ColWidth(ch(5)), RowHeight(ch(10))).into();
let size_2: Size = (RowHeight(ch(10)), ColWidth(ch(5))).into();
assert_eq!(size.col_width, ColWidth(ch(5)));
assert_eq!(*size.col_width, ch(5));
assert_eq!(size.row_height, RowHeight(ch(10)));
assert_eq!(*size.row_height, ch(10));
assert_eq!(size, size_2);
}
#[test]
fn test_size_add() {
let size1 = Size::new((ColWidth(5.into()), RowHeight(10.into())));
let size2 = Size::new((ColWidth::from(ch(3)), RowHeight::from(ch(4))));
let result = size1 + size2;
assert_eq!(result.col_width, ColWidth(8.into()));
assert_eq!(*result.col_width, ch(8));
assert_eq!(result.row_height, RowHeight(14.into()));
assert_eq!(*result.row_height, ch(14));
}
#[test]
fn test_size_sub() {
let size1 = Size::new((ColWidth(5.into()), RowHeight(10.into())));
let size2 = Size::new((ColWidth(3.into()), RowHeight(4.into())));
let result = size1 - size2;
assert_eq!(result.col_width, ColWidth(ch(2)));
assert_eq!(result.row_height, RowHeight(ch(6)));
}
#[test]
fn test_fits_min_size() {
let size = width(5) + height(10);
assert_eq!(
size.fits_min_size(Size::new((width(3), height(4)))),
SufficientSize::IsLargeEnough
);
assert_eq!(
size.fits_min_size(Size::new((width(100), height(100)))),
SufficientSize::IsTooSmall
);
}
#[test]
fn test_debug_fmt() {
let size = Size::new((width(5), height(10)));
assert_eq!(format!("{size:?}"), "[w: 5, h: 10]");
}
#[test]
fn test_ch_unit_sub_and_sub_assign() {
let mut size0 = Size::new((width(5), height(10)));
size0 -= ch(3);
assert_eq!(size0.col_width, ColWidth(ch(2)));
assert_eq!(size0.row_height, RowHeight(ch(7)));
let size1 = size0 - ch(1);
assert_eq!(size1.col_width, ColWidth(ch(1)));
assert_eq!(size1.row_height, RowHeight(ch(6)));
}
#[test]
fn test_ch_unit_add_and_add_assign() {
let mut size0 = Size::new((width(5), height(10)));
size0 += ch(3);
assert_eq!(size0.col_width, ColWidth(ch(8)));
assert_eq!(size0.row_height, RowHeight(ch(13)));
let size1 = size0 + ch(1);
assert_eq!(size1.col_width, ColWidth(ch(9)));
assert_eq!(size1.row_height, RowHeight(ch(14)));
}
#[test]
fn test_convert_dim_to_width_or_height() {
let size = width(5) + height(10);
let w: Width = size.into();
let h: Height = size.into();
assert_eq!(h, RowHeight(ch(10)));
assert_eq!(w, ColWidth(ch(5)));
}
}