use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
use std::time::Duration;
use intentional::{Cast, CastInto};
use crate::units::{Lp, Px, UPx, ARBITRARY_SCALE};
use crate::Fraction;
pub trait FloatConversion {
type Float;
fn into_float(self) -> Self::Float;
fn from_float(float: Self::Float) -> Self;
}
impl FloatConversion for u32 {
type Float = f32;
#[allow(clippy::cast_precision_loss)] fn into_float(self) -> Self::Float {
self as f32
}
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] fn from_float(float: Self::Float) -> Self {
assert!(float.is_sign_positive());
float as u32
}
}
impl FloatConversion for i32 {
type Float = f32;
#[allow(clippy::cast_precision_loss)] fn into_float(self) -> Self::Float {
self as f32
}
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] fn from_float(float: Self::Float) -> Self {
float as i32
}
}
pub trait Zero {
const ZERO: Self;
fn is_zero(&self) -> bool;
}
macro_rules! impl_int_zero {
($type:ident) => {
impl Zero for $type {
const ZERO: Self = 0;
fn is_zero(&self) -> bool {
*self == 0
}
}
};
}
impl_int_zero!(i8);
impl_int_zero!(i16);
impl_int_zero!(i32);
impl_int_zero!(i64);
impl_int_zero!(i128);
impl_int_zero!(isize);
impl_int_zero!(u8);
impl_int_zero!(u16);
impl_int_zero!(u32);
impl_int_zero!(u64);
impl_int_zero!(u128);
impl_int_zero!(usize);
pub trait Abs {
#[must_use]
fn abs(&self) -> Self;
}
macro_rules! impl_int_abs {
($type:ident) => {
impl Abs for $type {
fn abs(&self) -> Self {
self.saturating_abs()
}
}
};
}
impl_int_abs!(i8);
impl_int_abs!(i16);
impl_int_abs!(i32);
impl_int_abs!(i64);
impl_int_abs!(i128);
impl_int_abs!(isize);
impl Abs for f32 {
fn abs(&self) -> Self {
(*self).abs()
}
}
pub trait Pow {
#[must_use]
fn pow(&self, exp: u32) -> Self;
}
macro_rules! impl_int_pow {
($type:ident) => {
impl Pow for $type {
fn pow(&self, exp: u32) -> Self {
self.saturating_pow(exp)
}
}
};
}
impl_int_pow!(i8);
impl_int_pow!(i16);
impl_int_pow!(i32);
impl_int_pow!(i64);
impl_int_pow!(i128);
impl_int_pow!(isize);
impl_int_pow!(u8);
impl_int_pow!(u16);
impl_int_pow!(u32);
impl_int_pow!(u64);
impl_int_pow!(u128);
impl_int_pow!(usize);
impl Pow for f32 {
fn pow(&self, exp: u32) -> Self {
self.powf(exp.cast())
}
}
pub trait FromComponents<Unit>: Sized {
fn from_components(components: (Unit, Unit)) -> Self;
fn from_vec<Type>(other: Type) -> Self
where
Type: IntoComponents<Unit>,
{
Self::from_components(other.into_components())
}
}
pub trait Px2D: FromComponents<Px> {
fn px(x: impl Into<Px>, y: impl Into<Px>) -> Self {
Self::from_components((x.into(), y.into()))
}
}
impl<T> Px2D for T where T: FromComponents<Px> {}
pub trait UPx2D: FromComponents<UPx> {
fn upx(x: impl Into<UPx>, y: impl Into<UPx>) -> Self {
Self::from_components((x.into(), y.into()))
}
}
impl<T> UPx2D for T where T: FromComponents<UPx> {}
pub trait Lp2D: FromComponents<Lp> {
fn points(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
Self::from_components((x.into().into_points(), y.into().into_points()))
}
fn cm(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
Self::from_components((x.into().into_cm(), y.into().into_cm()))
}
fn mm(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
Self::from_components((x.into().into_mm(), y.into().into_mm()))
}
fn inches(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
Self::from_components((x.into().into_inches(), y.into().into_inches()))
}
}
impl<T> Lp2D for T where T: FromComponents<Lp> {}
#[derive(Clone, Copy)]
pub enum FloatOrInt {
Int(i32),
Float(f32),
}
impl FloatOrInt {
fn map<R>(self, float: impl FnOnce(f32) -> R, int: impl FnOnce(i32) -> R) -> R {
match self {
FloatOrInt::Int(value) => int(value),
FloatOrInt::Float(value) => float(value),
}
}
pub fn into_points(self) -> Lp {
self.map(Lp::points_f, Lp::points)
}
#[must_use]
pub fn into_cm(self) -> Lp {
self.map(Lp::cm_f, Lp::cm)
}
#[must_use]
pub fn into_mm(self) -> Lp {
self.map(Lp::mm_f, Lp::mm)
}
#[must_use]
pub fn into_inches(self) -> Lp {
self.map(Lp::inches_f, Lp::inches)
}
}
impl From<i32> for FloatOrInt {
fn from(value: i32) -> Self {
Self::Int(value)
}
}
impl From<f32> for FloatOrInt {
fn from(value: f32) -> Self {
Self::Float(value)
}
}
pub trait IntoComponents<Unit>: Sized {
fn into_components(self) -> (Unit, Unit);
fn to_vec<Type>(self) -> Type
where
Type: FromComponents<Unit>,
{
Type::from_vec(self)
}
}
impl<Unit> FromComponents<Unit> for (Unit, Unit) {
fn from_components(components: Self) -> Self {
components
}
}
impl<Unit> IntoComponents<Unit> for (Unit, Unit) {
fn into_components(self) -> Self {
self
}
}
impl<Unit> IntoComponents<Unit> for Unit
where
Unit: Copy,
{
fn into_components(self) -> (Unit, Unit) {
(self, self)
}
}
pub trait ScreenScale {
type Px;
type UPx;
type Lp;
fn into_px(self, scale: Fraction) -> Self::Px;
fn from_px(px: Self::Px, scale: Fraction) -> Self;
fn into_upx(self, scale: Fraction) -> Self::UPx;
fn from_upx(px: Self::UPx, scale: Fraction) -> Self;
fn into_lp(self, scale: Fraction) -> Self::Lp;
fn from_lp(lp: Self::Lp, scale: Fraction) -> Self;
}
pub trait IntoSigned {
type Signed;
#[must_use]
fn into_signed(self) -> Self::Signed;
}
impl IntoSigned for u32 {
type Signed = i32;
fn into_signed(self) -> Self::Signed {
self.try_into().unwrap_or(i32::MAX)
}
}
impl IntoSigned for i32 {
type Signed = Self;
fn into_signed(self) -> Self::Signed {
self
}
}
impl IntoSigned for f32 {
type Signed = Self;
fn into_signed(self) -> Self::Signed {
self
}
}
pub trait IntoUnsigned {
type Unsigned;
#[must_use]
fn into_unsigned(self) -> Self::Unsigned;
}
impl IntoUnsigned for i32 {
type Unsigned = u32;
fn into_unsigned(self) -> Self::Unsigned {
self.try_into().unwrap_or(0)
}
}
impl IntoUnsigned for u32 {
type Unsigned = Self;
fn into_unsigned(self) -> Self::Unsigned {
self
}
}
pub trait Unit:
FloatConversion<Float = f32>
+ Add<Output = Self>
+ Sub<Output = Self>
+ Div<Output = Self>
+ Mul<Output = Self>
+ Rem<Output = Self>
+ AddAssign
+ SubAssign
+ DivAssign
+ MulAssign
+ RemAssign
+ Zero
+ Ord
+ Eq
+ Copy
+ Default
+ std::fmt::Debug
+ IntoSigned
+ TryInto<i32>
+ 'static
{
}
pub trait StdNumOps {
fn saturating_add(self, other: Self) -> Self;
fn saturating_mul(self, other: Self) -> Self;
fn saturating_div(self, other: Self) -> Self;
fn saturating_sub(self, other: Self) -> Self;
}
macro_rules! impl_std_num_ops {
($type:ident) => {
impl StdNumOps for $type {
fn saturating_add(self, other: Self) -> Self {
self.saturating_add(other)
}
fn saturating_mul(self, other: Self) -> Self {
self.saturating_mul(other)
}
fn saturating_div(self, other: Self) -> Self {
self.saturating_div(other)
}
fn saturating_sub(self, other: Self) -> Self {
self.saturating_sub(other)
}
}
};
}
impl_std_num_ops!(u8);
impl<T> Unit for T where
T: FloatConversion<Float = f32>
+ Add<Output = Self>
+ Sub<Output = Self>
+ Div<Output = Self>
+ Mul<Output = Self>
+ Rem<Output = Self>
+ AddAssign
+ SubAssign
+ DivAssign
+ MulAssign
+ RemAssign
+ Zero
+ Ord
+ Eq
+ Copy
+ Default
+ std::fmt::Debug
+ IntoSigned
+ TryInto<i32>
+ 'static
{
}
pub trait ScreenUnit: UnscaledUnit + ScreenScale<Px = Px, Lp = Lp, UPx = UPx> + Unit {}
impl<T> ScreenUnit for T where T: UnscaledUnit + ScreenScale<Px = Px, Lp = Lp, UPx = UPx> + Unit {}
pub trait Ranged: Sized {
const MIN: Self;
const MAX: Self;
}
macro_rules! impl_int_ranged {
($type:ident) => {
impl Ranged for $type {
const MAX: Self = $type::MAX;
const MIN: Self = $type::MIN;
}
};
}
impl_int_ranged!(i8);
impl_int_ranged!(i16);
impl_int_ranged!(i32);
impl_int_ranged!(i64);
impl_int_ranged!(i128);
impl_int_ranged!(isize);
impl_int_ranged!(u8);
impl_int_ranged!(u16);
impl_int_ranged!(u32);
impl_int_ranged!(u64);
impl_int_ranged!(u128);
impl_int_ranged!(usize);
impl_int_ranged!(f32);
impl_int_ranged!(f64);
impl_int_ranged!(Px);
impl_int_ranged!(UPx);
impl_int_ranged!(Lp);
impl Ranged for Duration {
const MAX: Self = Duration::MAX;
const MIN: Self = Duration::ZERO;
}
impl Ranged for bool {
const MAX: Self = true;
const MIN: Self = false;
}
pub trait PixelScaling {
const PX_SCALING_FACTOR: u16;
}
impl PixelScaling for Px {
const PX_SCALING_FACTOR: u16 = 1;
}
impl PixelScaling for UPx {
const PX_SCALING_FACTOR: u16 = 1;
}
impl PixelScaling for Lp {
const PX_SCALING_FACTOR: u16 = ARBITRARY_SCALE; }
pub trait UnscaledUnit {
type Representation: CastInto<i32>;
fn from_unscaled(unscaled: Self::Representation) -> Self;
fn into_unscaled(self) -> Self::Representation;
}
pub trait Round {
#[must_use]
fn round(self) -> Self;
#[must_use]
fn ceil(self) -> Self;
#[must_use]
fn floor(self) -> Self;
}
impl Round for f32 {
fn round(self) -> Self {
self.round()
}
fn ceil(self) -> Self {
self.ceil()
}
fn floor(self) -> Self {
self.floor()
}
}
pub trait Roots {
#[must_use]
fn sqrt(self) -> Self;
#[must_use]
fn cbrt(self) -> Self;
}
impl Roots for f32 {
fn sqrt(self) -> Self {
self.sqrt()
}
fn cbrt(self) -> Self {
self.cbrt()
}
}