use std::ops::{Add, Div, Mul, Rem, Sub};
use num_traits::ToPrimitive;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Size {
pub width: u32,
pub height: u32,
}
impl Size {
pub fn new<W, H>(width: W, height: H) -> Self
where
W: ToPrimitive,
H: ToPrimitive,
{
let width = width.to_u32().unwrap_or_default();
let height = height.to_u32().unwrap_or_default();
Self { width, height }
}
pub const fn from_tuple((width, height): (u32, u32)) -> Self {
Self { width, height }
}
pub const fn as_tuple(&self) -> (u32, u32) {
(self.width, self.height)
}
pub const fn pixels(&self) -> usize {
self.width as usize * self.height as usize
}
pub(crate) const fn from_len(len: usize, width: usize) -> Self {
Self {
width: width as u32,
height: (len / width) as u32,
}
}
pub(crate) fn min(&self, other: Self) -> Self {
Self {
width: self.width.min(other.width),
height: self.height.min(other.height),
}
}
}
impl<W, H> From<(W, H)> for Size
where
W: ToPrimitive,
H: ToPrimitive,
{
fn from((width, height): (W, H)) -> Self {
let width = width.to_u32().unwrap_or_default();
let height = height.to_u32().unwrap_or_default();
Self { width, height }
}
}
impl Add<Size> for Size {
type Output = Self;
fn add(self, rhs: Size) -> Self::Output {
Self {
width: self.width + rhs.width,
height: self.height + rhs.height,
}
}
}
impl Sub<Size> for Size {
type Output = Self;
fn sub(self, rhs: Size) -> Self::Output {
Self {
width: self.width - rhs.width,
height: self.height - rhs.height,
}
}
}
impl Mul<Size> for Size {
type Output = Self;
fn mul(self, rhs: Size) -> Self::Output {
Self {
width: self.width * rhs.width,
height: self.height * rhs.height,
}
}
}
impl<T: ToPrimitive> Mul<T> for Size {
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
let rhs = rhs.to_u32().unwrap_or(1);
Self {
width: self.width * rhs,
height: self.height * rhs,
}
}
}
impl Div<Size> for Size {
type Output = Self;
fn div(self, rhs: Size) -> Self::Output {
Self {
width: self.width / rhs.width,
height: self.height / rhs.height,
}
}
}
impl<T: ToPrimitive> Div<T> for Size {
type Output = Self;
fn div(self, rhs: T) -> Self::Output {
let rhs = rhs.to_u32().unwrap_or(1);
Self {
width: self.width / rhs,
height: self.height / rhs,
}
}
}
impl Rem<Size> for Size {
type Output = Self;
fn rem(self, rhs: Size) -> Self::Output {
Self {
width: self.width % rhs.width,
height: self.height % rhs.height,
}
}
}
impl<T: ToPrimitive> Rem<T> for Size {
type Output = Self;
fn rem(self, rhs: T) -> Self::Output {
let rhs = rhs.to_u32().unwrap_or_default();
Self {
width: self.width % rhs,
height: self.height % rhs,
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubRect {
pub x: i32,
pub y: i32,
pub size: Size,
}
impl SubRect {
pub fn new<X, Y, S>(x: X, y: Y, size: S) -> Self
where
X: ToPrimitive,
Y: ToPrimitive,
S: Into<Size>,
{
let x = x.to_i32().unwrap_or_default();
let y = y.to_i32().unwrap_or_default();
let size = size.into();
Self { x, y, size }
}
pub fn from_size<S>(size: S) -> Self
where
S: Into<Size>,
{
let (x, y) = (0, 0);
let size = size.into();
Self { x, y, size }
}
pub fn shift<X, Y>(&self, new_x: X, new_y: Y) -> Self
where
X: ToPrimitive,
Y: ToPrimitive,
{
let new_x = new_x.to_i32().unwrap_or_default();
let new_y = new_y.to_i32().unwrap_or_default();
let (right, bottom) = (self.right(), self.bottom());
let (x, y) = (new_x.min(right), new_y.min(bottom));
let size = Size::new((right - self.x).max(0), (bottom - self.y).max(0));
Self { x, y, size }
}
pub fn width(&self) -> u32 {
self.size.width
}
pub fn height(&self) -> u32 {
self.size.height
}
pub fn right(&self) -> i32 {
self.x + self.width() as i32
}
pub fn bottom(&self) -> i32 {
self.y + self.height() as i32
}
pub fn as_slice(&self) -> (i32, i32, u32, u32) {
(self.x, self.y, self.size.width, self.size.height)
}
}
impl<X, Y, W, H> From<(X, Y, W, H)> for SubRect
where
X: ToPrimitive,
Y: ToPrimitive,
W: ToPrimitive,
H: ToPrimitive,
{
fn from((x, y, width, height): (X, Y, W, H)) -> Self {
let x = x.to_i32().unwrap_or(0);
let y = y.to_i32().unwrap_or(0);
let size = Size::from((width, height));
Self { x, y, size }
}
}