1use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
2use std::time::Duration;
3
4use intentional::{Cast, CastInto};
5
6use crate::units::{Lp, Px, UPx, ARBITRARY_SCALE};
7use crate::Fraction;
8
9pub trait FloatConversion {
13 type Float;
15
16 fn into_float(self) -> Self::Float;
18 fn from_float(float: Self::Float) -> Self;
20}
21
22impl FloatConversion for u32 {
23 type Float = f32;
24
25 #[allow(clippy::cast_precision_loss)] fn into_float(self) -> Self::Float {
27 self as f32
28 }
29
30 #[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] fn from_float(float: Self::Float) -> Self {
33 assert!(float.is_sign_positive());
34 float as u32
35 }
36}
37
38impl FloatConversion for i32 {
39 type Float = f32;
40
41 #[allow(clippy::cast_precision_loss)] fn into_float(self) -> Self::Float {
43 self as f32
44 }
45
46 #[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss)] fn from_float(float: Self::Float) -> Self {
49 float as i32
50 }
51}
52
53pub trait Zero {
55 const ZERO: Self;
57
58 fn is_zero(&self) -> bool;
60}
61
62macro_rules! impl_int_zero {
63 ($type:ident) => {
64 impl Zero for $type {
65 const ZERO: Self = 0;
66
67 fn is_zero(&self) -> bool {
68 *self == 0
69 }
70 }
71 };
72}
73
74impl_int_zero!(i8);
75impl_int_zero!(i16);
76impl_int_zero!(i32);
77impl_int_zero!(i64);
78impl_int_zero!(i128);
79impl_int_zero!(isize);
80impl_int_zero!(u8);
81impl_int_zero!(u16);
82impl_int_zero!(u32);
83impl_int_zero!(u64);
84impl_int_zero!(u128);
85impl_int_zero!(usize);
86
87pub trait Abs {
89 #[must_use]
94 fn abs(&self) -> Self;
95}
96
97macro_rules! impl_int_abs {
98 ($type:ident) => {
99 impl Abs for $type {
100 fn abs(&self) -> Self {
101 self.saturating_abs()
102 }
103 }
104 };
105}
106
107impl_int_abs!(i8);
108impl_int_abs!(i16);
109impl_int_abs!(i32);
110impl_int_abs!(i64);
111impl_int_abs!(i128);
112impl_int_abs!(isize);
113
114impl Abs for f32 {
115 fn abs(&self) -> Self {
116 (*self).abs()
117 }
118}
119
120pub trait Pow {
122 #[must_use]
124 fn pow(&self, exp: u32) -> Self;
125}
126
127macro_rules! impl_int_pow {
128 ($type:ident) => {
129 impl Pow for $type {
130 fn pow(&self, exp: u32) -> Self {
131 self.saturating_pow(exp)
132 }
133 }
134 };
135}
136
137impl_int_pow!(i8);
138impl_int_pow!(i16);
139impl_int_pow!(i32);
140impl_int_pow!(i64);
141impl_int_pow!(i128);
142impl_int_pow!(isize);
143impl_int_pow!(u8);
144impl_int_pow!(u16);
145impl_int_pow!(u32);
146impl_int_pow!(u64);
147impl_int_pow!(u128);
148impl_int_pow!(usize);
149
150impl Pow for f32 {
151 fn pow(&self, exp: u32) -> Self {
152 self.powf(exp.cast())
153 }
154}
155
156pub trait FromComponents<Unit>: Sized {
158 fn from_components(components: (Unit, Unit)) -> Self;
160
161 fn from_vec<Type>(other: Type) -> Self
164 where
165 Type: IntoComponents<Unit>,
166 {
167 Self::from_components(other.into_components())
168 }
169}
170
171pub trait Px2D: FromComponents<Px> {
173 fn px(x: impl Into<Px>, y: impl Into<Px>) -> Self {
176 Self::from_components((x.into(), y.into()))
177 }
178}
179
180impl<T> Px2D for T where T: FromComponents<Px> {}
181
182pub trait UPx2D: FromComponents<UPx> {
184 fn upx(x: impl Into<UPx>, y: impl Into<UPx>) -> Self {
187 Self::from_components((x.into(), y.into()))
188 }
189}
190
191impl<T> UPx2D for T where T: FromComponents<UPx> {}
192
193pub trait Lp2D: FromComponents<Lp> {
195 fn points(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
198 Self::from_components((x.into().into_points(), y.into().into_points()))
199 }
200
201 fn cm(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
204 Self::from_components((x.into().into_cm(), y.into().into_cm()))
205 }
206
207 fn mm(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
210 Self::from_components((x.into().into_mm(), y.into().into_mm()))
211 }
212
213 fn inches(x: impl Into<FloatOrInt>, y: impl Into<FloatOrInt>) -> Self {
216 Self::from_components((x.into().into_inches(), y.into().into_inches()))
217 }
218}
219
220impl<T> Lp2D for T where T: FromComponents<Lp> {}
221
222#[derive(Clone, Copy)]
224pub enum FloatOrInt {
225 Int(i32),
227 Float(f32),
229}
230
231impl FloatOrInt {
232 fn map<R>(self, float: impl FnOnce(f32) -> R, int: impl FnOnce(i32) -> R) -> R {
233 match self {
234 FloatOrInt::Int(value) => int(value),
235 FloatOrInt::Float(value) => float(value),
236 }
237 }
238
239 pub fn into_points(self) -> Lp {
241 self.map(Lp::points_f, Lp::points)
242 }
243
244 #[must_use]
246 pub fn into_cm(self) -> Lp {
247 self.map(Lp::cm_f, Lp::cm)
248 }
249
250 #[must_use]
252 pub fn into_mm(self) -> Lp {
253 self.map(Lp::mm_f, Lp::mm)
254 }
255
256 #[must_use]
258 pub fn into_inches(self) -> Lp {
259 self.map(Lp::inches_f, Lp::inches)
260 }
261}
262
263impl From<i32> for FloatOrInt {
264 fn from(value: i32) -> Self {
265 Self::Int(value)
266 }
267}
268
269impl From<f32> for FloatOrInt {
270 fn from(value: f32) -> Self {
271 Self::Float(value)
272 }
273}
274
275pub trait IntoComponents<Unit>: Sized {
277 fn into_components(self) -> (Unit, Unit);
279
280 fn to_vec<Type>(self) -> Type
283 where
284 Type: FromComponents<Unit>,
285 {
286 Type::from_vec(self)
287 }
288}
289
290impl<Unit> FromComponents<Unit> for (Unit, Unit) {
291 fn from_components(components: Self) -> Self {
292 components
293 }
294}
295
296impl<Unit> IntoComponents<Unit> for (Unit, Unit) {
297 fn into_components(self) -> Self {
298 self
299 }
300}
301
302impl<Unit> IntoComponents<Unit> for Unit
303where
304 Unit: Copy,
305{
306 fn into_components(self) -> (Unit, Unit) {
307 (self, self)
308 }
309}
310
311pub trait ScreenScale {
313 type Px;
315 type UPx;
317 type Lp;
319
320 fn into_px(self, scale: Fraction) -> Self::Px;
323 fn from_px(px: Self::Px, scale: Fraction) -> Self;
325
326 fn into_upx(self, scale: Fraction) -> Self::UPx;
329 fn from_upx(px: Self::UPx, scale: Fraction) -> Self;
331
332 fn into_lp(self, scale: Fraction) -> Self::Lp;
335 fn from_lp(lp: Self::Lp, scale: Fraction) -> Self;
337}
338
339pub trait IntoSigned {
342 type Signed;
344 #[must_use]
347 fn into_signed(self) -> Self::Signed;
348}
349
350impl IntoSigned for u32 {
351 type Signed = i32;
352
353 fn into_signed(self) -> Self::Signed {
354 self.try_into().unwrap_or(i32::MAX)
355 }
356}
357
358impl IntoSigned for i32 {
359 type Signed = Self;
360
361 fn into_signed(self) -> Self::Signed {
362 self
363 }
364}
365
366impl IntoSigned for f32 {
367 type Signed = Self;
368
369 fn into_signed(self) -> Self::Signed {
370 self
371 }
372}
373
374pub trait IntoUnsigned {
377 type Unsigned;
379 #[must_use]
382 fn into_unsigned(self) -> Self::Unsigned;
383}
384
385impl IntoUnsigned for i32 {
386 type Unsigned = u32;
387
388 fn into_unsigned(self) -> Self::Unsigned {
389 self.try_into().unwrap_or(0)
390 }
391}
392
393impl IntoUnsigned for u32 {
394 type Unsigned = Self;
395
396 fn into_unsigned(self) -> Self::Unsigned {
397 self
398 }
399}
400
401pub trait Unit:
403 FloatConversion<Float = f32>
404 + Add<Output = Self>
405 + Sub<Output = Self>
406 + Div<Output = Self>
407 + Mul<Output = Self>
408 + Rem<Output = Self>
409 + AddAssign
410 + SubAssign
411 + DivAssign
412 + MulAssign
413 + RemAssign
414 + Zero
415 + Ord
416 + Eq
417 + Copy
418 + Default
419 + std::fmt::Debug
420 + IntoSigned
421 + TryInto<i32>
422 + 'static
423{
424}
425
426pub trait StdNumOps {
429 fn saturating_add(self, other: Self) -> Self;
431 fn saturating_mul(self, other: Self) -> Self;
433 fn saturating_div(self, other: Self) -> Self;
435 fn saturating_sub(self, other: Self) -> Self;
437}
438
439macro_rules! impl_std_num_ops {
440 ($type:ident) => {
441 impl StdNumOps for $type {
442 fn saturating_add(self, other: Self) -> Self {
443 self.saturating_add(other)
444 }
445
446 fn saturating_mul(self, other: Self) -> Self {
447 self.saturating_mul(other)
448 }
449
450 fn saturating_div(self, other: Self) -> Self {
451 self.saturating_div(other)
452 }
453
454 fn saturating_sub(self, other: Self) -> Self {
455 self.saturating_sub(other)
456 }
457 }
458 };
459}
460
461impl_std_num_ops!(u8);
462
463impl<T> Unit for T where
464 T: FloatConversion<Float = f32>
465 + Add<Output = Self>
466 + Sub<Output = Self>
467 + Div<Output = Self>
468 + Mul<Output = Self>
469 + Rem<Output = Self>
470 + AddAssign
471 + SubAssign
472 + DivAssign
473 + MulAssign
474 + RemAssign
475 + Zero
476 + Ord
477 + Eq
478 + Copy
479 + Default
480 + std::fmt::Debug
481 + IntoSigned
482 + TryInto<i32>
483 + 'static
484{
485}
486
487pub trait ScreenUnit: UnscaledUnit + ScreenScale<Px = Px, Lp = Lp, UPx = UPx> + Unit {}
490
491impl<T> ScreenUnit for T where T: UnscaledUnit + ScreenScale<Px = Px, Lp = Lp, UPx = UPx> + Unit {}
492
493pub trait Ranged: Sized {
495 const MIN: Self;
497 const MAX: Self;
499}
500
501macro_rules! impl_int_ranged {
502 ($type:ident) => {
503 impl Ranged for $type {
504 const MAX: Self = $type::MAX;
505 const MIN: Self = $type::MIN;
506 }
507 };
508}
509
510impl_int_ranged!(i8);
511impl_int_ranged!(i16);
512impl_int_ranged!(i32);
513impl_int_ranged!(i64);
514impl_int_ranged!(i128);
515impl_int_ranged!(isize);
516impl_int_ranged!(u8);
517impl_int_ranged!(u16);
518impl_int_ranged!(u32);
519impl_int_ranged!(u64);
520impl_int_ranged!(u128);
521impl_int_ranged!(usize);
522impl_int_ranged!(f32);
523impl_int_ranged!(f64);
524impl_int_ranged!(Px);
525impl_int_ranged!(UPx);
526impl_int_ranged!(Lp);
527
528impl Ranged for Duration {
529 const MAX: Self = Duration::MAX;
530 const MIN: Self = Duration::ZERO;
531}
532
533impl Ranged for bool {
534 const MAX: Self = true;
535 const MIN: Self = false;
536}
537
538pub trait PixelScaling {
540 const PX_SCALING_FACTOR: u16;
543}
544
545impl PixelScaling for Px {
546 const PX_SCALING_FACTOR: u16 = 1;
547}
548
549impl PixelScaling for UPx {
550 const PX_SCALING_FACTOR: u16 = 1;
551}
552
553impl PixelScaling for Lp {
554 const PX_SCALING_FACTOR: u16 = ARBITRARY_SCALE; }
556
557pub trait UnscaledUnit {
559 type Representation: CastInto<i32>;
561
562 fn from_unscaled(unscaled: Self::Representation) -> Self;
564 fn into_unscaled(self) -> Self::Representation;
566}
567
568pub trait Round {
570 #[must_use]
572 fn round(self) -> Self;
573 #[must_use]
575 fn ceil(self) -> Self;
576 #[must_use]
578 fn floor(self) -> Self;
579}
580
581impl Round for f32 {
582 fn round(self) -> Self {
583 self.round()
584 }
585
586 fn ceil(self) -> Self {
587 self.ceil()
588 }
589
590 fn floor(self) -> Self {
591 self.floor()
592 }
593}
594
595pub trait Roots {
597 #[must_use]
599 fn sqrt(self) -> Self;
600
601 #[must_use]
603 fn cbrt(self) -> Self;
604}
605
606impl Roots for f32 {
607 fn sqrt(self) -> Self {
608 self.sqrt()
609 }
610
611 fn cbrt(self) -> Self {
612 self.cbrt()
613 }
614}