1#![cfg_attr(docsrs, feature(doc_cfg), doc(auto_cfg(hide(doc, docsrs))))]
68#![cfg_attr(feature = "std", forbid(unsafe_code))]
69#![no_std]
70
71#[cfg(not(feature = "std"))]
72mod libm;
73
74#[cfg(any(feature = "std", test))]
75extern crate std;
76
77#[cfg(feature = "serde")]
78use serde::{Deserialize, Serialize};
79
80pub trait Pixel: Copy + Into<f64> {
81 fn from_f64(f: f64) -> Self;
82 fn cast<P: Pixel>(self) -> P {
83 P::from_f64(self.into())
84 }
85}
86
87macro_rules! pixel_int_impl {
88 ($($t:ty),*) => {$(
89 impl Pixel for $t {
90 fn from_f64(f: f64) -> Self {
91 round(f) as $t
92 }
93 }
94 )*}
95}
96
97pixel_int_impl!(u8, u16, u32, i8, i16, i32);
98
99impl Pixel for f32 {
100 fn from_f64(f: f64) -> Self {
101 f as f32
102 }
103}
104impl Pixel for f64 {
105 fn from_f64(f: f64) -> Self {
106 f
107 }
108}
109
110#[inline]
112fn round(f: f64) -> f64 {
113 #[cfg(feature = "std")]
114 return f.round();
115 #[cfg(not(feature = "std"))]
116 return libm::round(f);
117}
118
119#[inline]
125pub fn validate_scale_factor(scale_factor: f64) -> bool {
126 scale_factor.is_sign_positive() && scale_factor.is_normal()
127}
128
129#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
131#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
132pub struct LogicalUnit<P>(pub P);
133
134impl<P> LogicalUnit<P> {
135 pub const MAX: LogicalUnit<f64> = LogicalUnit::new(f64::MAX);
137 pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN);
139 pub const ZERO: LogicalUnit<f64> = LogicalUnit::new(0.0);
141
142 #[inline]
143 pub const fn new(v: P) -> Self {
144 LogicalUnit(v)
145 }
146}
147
148impl<P: Pixel> LogicalUnit<P> {
149 #[inline]
150 pub fn from_physical<T: Into<PhysicalUnit<X>>, X: Pixel>(
151 physical: T,
152 scale_factor: f64,
153 ) -> Self {
154 physical.into().to_logical(scale_factor)
155 }
156
157 #[inline]
158 pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<X> {
159 assert!(validate_scale_factor(scale_factor));
160 PhysicalUnit::new(self.0.into() * scale_factor).cast()
161 }
162
163 #[inline]
164 pub fn cast<X: Pixel>(&self) -> LogicalUnit<X> {
165 LogicalUnit(self.0.cast())
166 }
167}
168
169impl<P: Pixel, X: Pixel> From<X> for LogicalUnit<P> {
170 fn from(v: X) -> LogicalUnit<P> {
171 LogicalUnit::new(v.cast())
172 }
173}
174
175impl<P: Pixel> From<LogicalUnit<P>> for u8 {
176 fn from(v: LogicalUnit<P>) -> u8 {
177 v.0.cast()
178 }
179}
180
181impl<P: Pixel> From<LogicalUnit<P>> for u16 {
182 fn from(v: LogicalUnit<P>) -> u16 {
183 v.0.cast()
184 }
185}
186
187impl<P: Pixel> From<LogicalUnit<P>> for u32 {
188 fn from(v: LogicalUnit<P>) -> u32 {
189 v.0.cast()
190 }
191}
192
193impl<P: Pixel> From<LogicalUnit<P>> for i8 {
194 fn from(v: LogicalUnit<P>) -> i8 {
195 v.0.cast()
196 }
197}
198
199impl<P: Pixel> From<LogicalUnit<P>> for i16 {
200 fn from(v: LogicalUnit<P>) -> i16 {
201 v.0.cast()
202 }
203}
204
205impl<P: Pixel> From<LogicalUnit<P>> for i32 {
206 fn from(v: LogicalUnit<P>) -> i32 {
207 v.0.cast()
208 }
209}
210
211impl<P: Pixel> From<LogicalUnit<P>> for f32 {
212 fn from(v: LogicalUnit<P>) -> f32 {
213 v.0.cast()
214 }
215}
216
217impl<P: Pixel> From<LogicalUnit<P>> for f64 {
218 fn from(v: LogicalUnit<P>) -> f64 {
219 v.0.cast()
220 }
221}
222
223#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
225#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
226pub struct PhysicalUnit<P>(pub P);
227
228impl<P> PhysicalUnit<P> {
229 pub const MAX: LogicalUnit<f64> = LogicalUnit::new(f64::MAX);
231 pub const MIN: LogicalUnit<f64> = LogicalUnit::new(f64::MIN);
233 pub const ZERO: LogicalUnit<f64> = LogicalUnit::new(0.0);
235
236 #[inline]
237 pub const fn new(v: P) -> Self {
238 PhysicalUnit(v)
239 }
240}
241
242impl<P: Pixel> PhysicalUnit<P> {
243 #[inline]
244 pub fn from_logical<T: Into<LogicalUnit<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
245 logical.into().to_physical(scale_factor)
246 }
247
248 #[inline]
249 pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalUnit<X> {
250 assert!(validate_scale_factor(scale_factor));
251 LogicalUnit::new(self.0.into() / scale_factor).cast()
252 }
253
254 #[inline]
255 pub fn cast<X: Pixel>(&self) -> PhysicalUnit<X> {
256 PhysicalUnit(self.0.cast())
257 }
258}
259
260impl<P: Pixel, X: Pixel> From<X> for PhysicalUnit<P> {
261 fn from(v: X) -> PhysicalUnit<P> {
262 PhysicalUnit::new(v.cast())
263 }
264}
265
266impl<P: Pixel> From<PhysicalUnit<P>> for u8 {
267 fn from(v: PhysicalUnit<P>) -> u8 {
268 v.0.cast()
269 }
270}
271
272impl<P: Pixel> From<PhysicalUnit<P>> for u16 {
273 fn from(v: PhysicalUnit<P>) -> u16 {
274 v.0.cast()
275 }
276}
277
278impl<P: Pixel> From<PhysicalUnit<P>> for u32 {
279 fn from(v: PhysicalUnit<P>) -> u32 {
280 v.0.cast()
281 }
282}
283
284impl<P: Pixel> From<PhysicalUnit<P>> for i8 {
285 fn from(v: PhysicalUnit<P>) -> i8 {
286 v.0.cast()
287 }
288}
289
290impl<P: Pixel> From<PhysicalUnit<P>> for i16 {
291 fn from(v: PhysicalUnit<P>) -> i16 {
292 v.0.cast()
293 }
294}
295
296impl<P: Pixel> From<PhysicalUnit<P>> for i32 {
297 fn from(v: PhysicalUnit<P>) -> i32 {
298 v.0.cast()
299 }
300}
301
302impl<P: Pixel> From<PhysicalUnit<P>> for f32 {
303 fn from(v: PhysicalUnit<P>) -> f32 {
304 v.0.cast()
305 }
306}
307
308impl<P: Pixel> From<PhysicalUnit<P>> for f64 {
309 fn from(v: PhysicalUnit<P>) -> f64 {
310 v.0.cast()
311 }
312}
313
314#[derive(Debug, Copy, Clone, PartialEq)]
316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
317pub enum PixelUnit {
318 Physical(PhysicalUnit<i32>),
319 Logical(LogicalUnit<f64>),
320}
321
322impl PixelUnit {
323 pub const MAX: PixelUnit = PixelUnit::Logical(LogicalUnit::new(f64::MAX));
325 pub const MIN: PixelUnit = PixelUnit::Logical(LogicalUnit::new(f64::MIN));
327 pub const ZERO: PixelUnit = PixelUnit::Logical(LogicalUnit::new(0.0));
329
330 pub fn new<S: Into<PixelUnit>>(unit: S) -> PixelUnit {
331 unit.into()
332 }
333
334 pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalUnit<P> {
335 match *self {
336 PixelUnit::Physical(unit) => unit.to_logical(scale_factor),
337 PixelUnit::Logical(unit) => unit.cast(),
338 }
339 }
340
341 pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<P> {
342 match *self {
343 PixelUnit::Physical(unit) => unit.cast(),
344 PixelUnit::Logical(unit) => unit.to_physical(scale_factor),
345 }
346 }
347}
348
349impl<P: Pixel> From<PhysicalUnit<P>> for PixelUnit {
350 #[inline]
351 fn from(unit: PhysicalUnit<P>) -> PixelUnit {
352 PixelUnit::Physical(unit.cast())
353 }
354}
355
356impl<P: Pixel> From<LogicalUnit<P>> for PixelUnit {
357 #[inline]
358 fn from(unit: LogicalUnit<P>) -> PixelUnit {
359 PixelUnit::Logical(unit.cast())
360 }
361}
362
363macro_rules! vec2_from_impls {
364 ($t:ident, $a:ident, $b:ident, $mint_ty:ident) => {
365 impl<P: Pixel, X: Pixel> From<(X, X)> for $t<P> {
366 fn from(($a, $b): (X, X)) -> Self {
367 Self::new($a.cast(), $b.cast())
368 }
369 }
370
371 impl<P: Pixel, X: Pixel> From<$t<P>> for (X, X) {
372 fn from(p: $t<P>) -> Self {
373 (p.$a.cast(), p.$b.cast())
374 }
375 }
376
377 impl<P: Pixel, X: Pixel> From<[X; 2]> for $t<P> {
378 fn from([$a, $b]: [X; 2]) -> Self {
379 Self::new($a.cast(), $b.cast())
380 }
381 }
382
383 impl<P: Pixel, X: Pixel> From<$t<P>> for [X; 2] {
384 fn from(p: $t<P>) -> Self {
385 [p.$a.cast(), p.$b.cast()]
386 }
387 }
388
389 #[cfg(feature = "mint")]
390 impl<P: Pixel> From<mint::$mint_ty<P>> for $t<P> {
391 fn from(p: mint::$mint_ty<P>) -> Self {
392 Self::new(p.x, p.y)
393 }
394 }
395
396 #[cfg(feature = "mint")]
397 impl<P: Pixel> From<$t<P>> for mint::$mint_ty<P> {
398 fn from(p: $t<P>) -> Self {
399 Self { x: p.$a, y: p.$b }
400 }
401 }
402 };
403}
404
405#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
411#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
412pub struct LogicalPosition<P> {
413 pub x: P,
414 pub y: P,
415}
416
417impl<P> LogicalPosition<P> {
418 #[inline]
419 pub const fn new(x: P, y: P) -> Self {
420 LogicalPosition { x, y }
421 }
422}
423
424impl<P: Pixel> LogicalPosition<P> {
425 #[inline]
426 pub fn from_physical<T: Into<PhysicalPosition<X>>, X: Pixel>(
427 physical: T,
428 scale_factor: f64,
429 ) -> Self {
430 physical.into().to_logical(scale_factor)
431 }
432
433 #[inline]
434 pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<X> {
435 assert!(validate_scale_factor(scale_factor));
436 let x = self.x.into() * scale_factor;
437 let y = self.y.into() * scale_factor;
438 PhysicalPosition::new(x, y).cast()
439 }
440
441 #[inline]
442 pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> {
443 LogicalPosition { x: self.x.cast(), y: self.y.cast() }
444 }
445}
446
447vec2_from_impls!(LogicalPosition, x, y, Point2);
448
449#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
451#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
452pub struct PhysicalPosition<P> {
453 pub x: P,
454 pub y: P,
455}
456
457impl<P> PhysicalPosition<P> {
458 #[inline]
459 pub const fn new(x: P, y: P) -> Self {
460 PhysicalPosition { x, y }
461 }
462}
463
464impl<P: Pixel> PhysicalPosition<P> {
465 #[inline]
466 pub fn from_logical<T: Into<LogicalPosition<X>>, X: Pixel>(
467 logical: T,
468 scale_factor: f64,
469 ) -> Self {
470 logical.into().to_physical(scale_factor)
471 }
472
473 #[inline]
474 pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalPosition<X> {
475 assert!(validate_scale_factor(scale_factor));
476 let x = self.x.into() / scale_factor;
477 let y = self.y.into() / scale_factor;
478 LogicalPosition::new(x, y).cast()
479 }
480
481 #[inline]
482 pub fn cast<X: Pixel>(&self) -> PhysicalPosition<X> {
483 PhysicalPosition { x: self.x.cast(), y: self.y.cast() }
484 }
485}
486
487vec2_from_impls!(PhysicalPosition, x, y, Point2);
488
489#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
491#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
492pub struct LogicalSize<P> {
493 pub width: P,
494 pub height: P,
495}
496
497impl<P> LogicalSize<P> {
498 #[inline]
499 pub const fn new(width: P, height: P) -> Self {
500 LogicalSize { width, height }
501 }
502}
503
504impl<P: Pixel> LogicalSize<P> {
505 #[inline]
506 pub fn from_physical<T: Into<PhysicalSize<X>>, X: Pixel>(
507 physical: T,
508 scale_factor: f64,
509 ) -> Self {
510 physical.into().to_logical(scale_factor)
511 }
512
513 #[inline]
514 pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalSize<X> {
515 assert!(validate_scale_factor(scale_factor));
516 let width = self.width.into() * scale_factor;
517 let height = self.height.into() * scale_factor;
518 PhysicalSize::new(width, height).cast()
519 }
520
521 #[inline]
522 pub fn cast<X: Pixel>(&self) -> LogicalSize<X> {
523 LogicalSize { width: self.width.cast(), height: self.height.cast() }
524 }
525}
526
527vec2_from_impls!(LogicalSize, width, height, Vector2);
528
529#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
531#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
532pub struct PhysicalSize<P> {
533 pub width: P,
534 pub height: P,
535}
536
537impl<P> PhysicalSize<P> {
538 #[inline]
539 pub const fn new(width: P, height: P) -> Self {
540 PhysicalSize { width, height }
541 }
542}
543
544impl<P: Pixel> PhysicalSize<P> {
545 #[inline]
546 pub fn from_logical<T: Into<LogicalSize<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
547 logical.into().to_physical(scale_factor)
548 }
549
550 #[inline]
551 pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalSize<X> {
552 assert!(validate_scale_factor(scale_factor));
553 let width = self.width.into() / scale_factor;
554 let height = self.height.into() / scale_factor;
555 LogicalSize::new(width, height).cast()
556 }
557
558 #[inline]
559 pub fn cast<X: Pixel>(&self) -> PhysicalSize<X> {
560 PhysicalSize { width: self.width.cast(), height: self.height.cast() }
561 }
562}
563
564vec2_from_impls!(PhysicalSize, width, height, Vector2);
565
566#[derive(Debug, Copy, Clone, PartialEq)]
568#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
569pub enum Size {
570 Physical(PhysicalSize<u32>),
571 Logical(LogicalSize<f64>),
572}
573
574impl Size {
575 pub fn new<S: Into<Size>>(size: S) -> Size {
576 size.into()
577 }
578
579 pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalSize<P> {
580 match *self {
581 Size::Physical(size) => size.to_logical(scale_factor),
582 Size::Logical(size) => size.cast(),
583 }
584 }
585
586 pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalSize<P> {
587 match *self {
588 Size::Physical(size) => size.cast(),
589 Size::Logical(size) => size.to_physical(scale_factor),
590 }
591 }
592
593 pub fn clamp<S: Into<Size>>(input: S, min: S, max: S, scale_factor: f64) -> Size {
594 let (input, min, max) = (
595 input.into().to_physical::<f64>(scale_factor),
596 min.into().to_physical::<f64>(scale_factor),
597 max.into().to_physical::<f64>(scale_factor),
598 );
599
600 let width = input.width.clamp(min.width, max.width);
601 let height = input.height.clamp(min.height, max.height);
602
603 PhysicalSize::new(width, height).into()
604 }
605}
606
607impl<P: Pixel> From<PhysicalSize<P>> for Size {
608 #[inline]
609 fn from(size: PhysicalSize<P>) -> Size {
610 Size::Physical(size.cast())
611 }
612}
613
614impl<P: Pixel> From<LogicalSize<P>> for Size {
615 #[inline]
616 fn from(size: LogicalSize<P>) -> Size {
617 Size::Logical(size.cast())
618 }
619}
620
621#[derive(Debug, Copy, Clone, PartialEq)]
623#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
624pub enum Position {
625 Physical(PhysicalPosition<i32>),
626 Logical(LogicalPosition<f64>),
627}
628
629impl Position {
630 pub fn new<S: Into<Position>>(position: S) -> Position {
631 position.into()
632 }
633
634 pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalPosition<P> {
635 match *self {
636 Position::Physical(position) => position.to_logical(scale_factor),
637 Position::Logical(position) => position.cast(),
638 }
639 }
640
641 pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<P> {
642 match *self {
643 Position::Physical(position) => position.cast(),
644 Position::Logical(position) => position.to_physical(scale_factor),
645 }
646 }
647}
648
649impl<P: Pixel> From<PhysicalPosition<P>> for Position {
650 #[inline]
651 fn from(position: PhysicalPosition<P>) -> Position {
652 Position::Physical(position.cast())
653 }
654}
655
656impl<P: Pixel> From<LogicalPosition<P>> for Position {
657 #[inline]
658 fn from(position: LogicalPosition<P>) -> Position {
659 Position::Logical(position.cast())
660 }
661}
662
663#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
665#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
666pub struct LogicalInsets<P> {
667 pub top: P,
669 pub left: P,
671 pub bottom: P,
673 pub right: P,
675}
676
677impl<P> LogicalInsets<P> {
678 #[inline]
679 pub const fn new(top: P, left: P, bottom: P, right: P) -> Self {
680 Self { top, left, bottom, right }
681 }
682}
683
684impl<P: Pixel> LogicalInsets<P> {
685 #[inline]
686 pub fn from_physical<T: Into<PhysicalInsets<X>>, X: Pixel>(
687 physical: T,
688 scale_factor: f64,
689 ) -> Self {
690 physical.into().to_logical(scale_factor)
691 }
692
693 #[inline]
694 pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalInsets<X> {
695 assert!(validate_scale_factor(scale_factor));
696 let top = self.top.into() * scale_factor;
697 let left = self.left.into() * scale_factor;
698 let bottom = self.bottom.into() * scale_factor;
699 let right = self.right.into() * scale_factor;
700 PhysicalInsets::new(top, left, bottom, right).cast()
701 }
702
703 #[inline]
704 pub fn cast<X: Pixel>(&self) -> LogicalInsets<X> {
705 LogicalInsets {
706 top: self.top.cast(),
707 left: self.left.cast(),
708 bottom: self.bottom.cast(),
709 right: self.right.cast(),
710 }
711 }
712}
713
714#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
716#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
717pub struct PhysicalInsets<P> {
718 pub top: P,
720 pub left: P,
722 pub bottom: P,
724 pub right: P,
726}
727
728impl<P> PhysicalInsets<P> {
729 #[inline]
730 pub const fn new(top: P, left: P, bottom: P, right: P) -> Self {
731 Self { top, left, bottom, right }
732 }
733}
734
735impl<P: Pixel> PhysicalInsets<P> {
736 #[inline]
737 pub fn from_logical<T: Into<LogicalInsets<X>>, X: Pixel>(
738 logical: T,
739 scale_factor: f64,
740 ) -> Self {
741 logical.into().to_physical(scale_factor)
742 }
743
744 #[inline]
745 pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalInsets<X> {
746 assert!(validate_scale_factor(scale_factor));
747 let top = self.top.into() / scale_factor;
748 let left = self.left.into() / scale_factor;
749 let bottom = self.bottom.into() / scale_factor;
750 let right = self.right.into() / scale_factor;
751 LogicalInsets::new(top, left, bottom, right).cast()
752 }
753
754 #[inline]
755 pub fn cast<X: Pixel>(&self) -> PhysicalInsets<X> {
756 PhysicalInsets {
757 top: self.top.cast(),
758 left: self.left.cast(),
759 bottom: self.bottom.cast(),
760 right: self.right.cast(),
761 }
762 }
763}
764
765#[derive(Debug, Copy, Clone, PartialEq)]
767#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
768pub enum Insets {
769 Physical(PhysicalInsets<u32>),
770 Logical(LogicalInsets<f64>),
771}
772
773impl Insets {
774 pub fn new<S: Into<Self>>(insets: S) -> Self {
775 insets.into()
776 }
777
778 pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalInsets<P> {
779 match *self {
780 Self::Physical(insets) => insets.to_logical(scale_factor),
781 Self::Logical(insets) => insets.cast(),
782 }
783 }
784
785 pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalInsets<P> {
786 match *self {
787 Self::Physical(insets) => insets.cast(),
788 Self::Logical(insets) => insets.to_physical(scale_factor),
789 }
790 }
791}
792
793impl<P: Pixel> From<PhysicalInsets<P>> for Insets {
794 #[inline]
795 fn from(insets: PhysicalInsets<P>) -> Self {
796 Self::Physical(insets.cast())
797 }
798}
799
800impl<P: Pixel> From<LogicalInsets<P>> for Insets {
801 #[inline]
802 fn from(insets: LogicalInsets<P>) -> Self {
803 Self::Logical(insets.cast())
804 }
805}
806
807#[cfg(test)]
808mod tests {
809 use std::collections::HashSet;
810
811 use super::*;
812
813 macro_rules! test_pixel_int_impl {
814 ($($name:ident => $ty:ty),*) => {$(
815 #[test]
816 fn $name() {
817 assert_eq!(
818 <$ty as Pixel>::from_f64(37.0),
819 37,
820 );
821 assert_eq!(
822 <$ty as Pixel>::from_f64(37.4),
823 37,
824 );
825 assert_eq!(
826 <$ty as Pixel>::from_f64(37.5),
827 38,
828 );
829 assert_eq!(
830 <$ty as Pixel>::from_f64(37.9),
831 38,
832 );
833
834 assert_eq!(
835 <$ty as Pixel>::cast::<u8>(37),
836 37,
837 );
838 assert_eq!(
839 <$ty as Pixel>::cast::<u16>(37),
840 37,
841 );
842 assert_eq!(
843 <$ty as Pixel>::cast::<u32>(37),
844 37,
845 );
846 assert_eq!(
847 <$ty as Pixel>::cast::<i8>(37),
848 37,
849 );
850 assert_eq!(
851 <$ty as Pixel>::cast::<i16>(37),
852 37,
853 );
854 assert_eq!(
855 <$ty as Pixel>::cast::<i32>(37),
856 37,
857 );
858 }
859 )*};
860 }
861
862 test_pixel_int_impl! {
863 test_pixel_int_u8 => u8,
864 test_pixel_int_u16 => u16,
865 test_pixel_int_u32 => u32,
866 test_pixel_int_i8 => i8,
867 test_pixel_int_i16 => i16
868 }
869
870 macro_rules! assert_approx_eq {
871 ($a:expr, $b:expr $(,)?) => {
872 assert!(($a - $b).abs() < 0.001, "{} is not approximately equal to {}", $a, $b);
873 };
874 }
875
876 macro_rules! test_pixel_float_impl {
877 ($($name:ident => $ty:ty),*) => {$(
878 #[test]
879 fn $name() {
880 assert_approx_eq!(
881 <$ty as Pixel>::from_f64(37.0),
882 37.0,
883 );
884 assert_approx_eq!(
885 <$ty as Pixel>::from_f64(37.4),
886 37.4,
887 );
888 assert_approx_eq!(
889 <$ty as Pixel>::from_f64(37.5),
890 37.5,
891 );
892 assert_approx_eq!(
893 <$ty as Pixel>::from_f64(37.9),
894 37.9,
895 );
896
897 assert_eq!(
898 <$ty as Pixel>::cast::<u8>(37.0),
899 37,
900 );
901 assert_eq!(
902 <$ty as Pixel>::cast::<u8>(37.4),
903 37,
904 );
905 assert_eq!(
906 <$ty as Pixel>::cast::<u8>(37.5),
907 38,
908 );
909
910 assert_eq!(
911 <$ty as Pixel>::cast::<u16>(37.0),
912 37,
913 );
914 assert_eq!(
915 <$ty as Pixel>::cast::<u16>(37.4),
916 37,
917 );
918 assert_eq!(
919 <$ty as Pixel>::cast::<u16>(37.5),
920 38,
921 );
922
923 assert_eq!(
924 <$ty as Pixel>::cast::<u32>(37.0),
925 37,
926 );
927 assert_eq!(
928 <$ty as Pixel>::cast::<u32>(37.4),
929 37,
930 );
931 assert_eq!(
932 <$ty as Pixel>::cast::<u32>(37.5),
933 38,
934 );
935
936 assert_eq!(
937 <$ty as Pixel>::cast::<i8>(37.0),
938 37,
939 );
940 assert_eq!(
941 <$ty as Pixel>::cast::<i8>(37.4),
942 37,
943 );
944 assert_eq!(
945 <$ty as Pixel>::cast::<i8>(37.5),
946 38,
947 );
948
949 assert_eq!(
950 <$ty as Pixel>::cast::<i16>(37.0),
951 37,
952 );
953 assert_eq!(
954 <$ty as Pixel>::cast::<i16>(37.4),
955 37,
956 );
957 assert_eq!(
958 <$ty as Pixel>::cast::<i16>(37.5),
959 38,
960 );
961 }
962 )*};
963}
964
965 test_pixel_float_impl! {
966 test_pixel_float_f32 => f32,
967 test_pixel_float_f64 => f64
968 }
969
970 #[test]
971 fn test_validate_scale_factor() {
972 assert!(validate_scale_factor(1.0));
973 assert!(validate_scale_factor(2.0));
974 assert!(validate_scale_factor(3.0));
975 assert!(validate_scale_factor(1.5));
976 assert!(validate_scale_factor(0.5));
977
978 assert!(!validate_scale_factor(0.0));
979 assert!(!validate_scale_factor(-1.0));
980 assert!(!validate_scale_factor(f64::INFINITY));
981 assert!(!validate_scale_factor(f64::NAN));
982 assert!(!validate_scale_factor(f64::NEG_INFINITY));
983 }
984
985 #[test]
986 fn test_logical_unity() {
987 let log_unit = LogicalUnit::new(1.0);
988 assert_eq!(log_unit.to_physical::<u32>(1.0), PhysicalUnit::new(1));
989 assert_eq!(log_unit.to_physical::<u32>(2.0), PhysicalUnit::new(2));
990 assert_eq!(log_unit.cast::<u32>(), LogicalUnit::new(1));
991 assert_eq!(log_unit, LogicalUnit::from_physical(PhysicalUnit::new(1.0), 1.0));
992 assert_eq!(log_unit, LogicalUnit::from_physical(PhysicalUnit::new(2.0), 2.0));
993 assert_eq!(LogicalUnit::from(2.0), LogicalUnit::new(2.0));
994
995 let x: f64 = log_unit.into();
996 assert_eq!(x, 1.0);
997 }
998
999 #[test]
1000 fn test_physical_unit() {
1001 assert_eq!(PhysicalUnit::from_logical(LogicalUnit::new(1.0), 1.0), PhysicalUnit::new(1));
1002 assert_eq!(PhysicalUnit::from_logical(LogicalUnit::new(2.0), 0.5), PhysicalUnit::new(1));
1003 assert_eq!(PhysicalUnit::from(2.0), PhysicalUnit::new(2.0,));
1004 assert_eq!(PhysicalUnit::from(2.0), PhysicalUnit::new(2.0));
1005
1006 let x: f64 = PhysicalUnit::new(1).into();
1007 assert_eq!(x, 1.0);
1008 }
1009
1010 #[test]
1011 fn test_logical_position() {
1012 let log_pos = LogicalPosition::new(1.0, 2.0);
1013 assert_eq!(log_pos.to_physical::<u32>(1.0), PhysicalPosition::new(1, 2));
1014 assert_eq!(log_pos.to_physical::<u32>(2.0), PhysicalPosition::new(2, 4));
1015 assert_eq!(log_pos.cast::<u32>(), LogicalPosition::new(1, 2));
1016 assert_eq!(log_pos, LogicalPosition::from_physical(PhysicalPosition::new(1.0, 2.0), 1.0));
1017 assert_eq!(log_pos, LogicalPosition::from_physical(PhysicalPosition::new(2.0, 4.0), 2.0));
1018 assert_eq!(LogicalPosition::from((2.0, 2.0)), LogicalPosition::new(2.0, 2.0));
1019 assert_eq!(LogicalPosition::from([2.0, 3.0]), LogicalPosition::new(2.0, 3.0));
1020
1021 let x: (f64, f64) = log_pos.into();
1022 assert_eq!(x, (1.0, 2.0));
1023 let x: [f64; 2] = log_pos.into();
1024 assert_eq!(x, [1.0, 2.0]);
1025 }
1026
1027 #[test]
1028 fn test_physical_position() {
1029 assert_eq!(
1030 PhysicalPosition::from_logical(LogicalPosition::new(1.0, 2.0), 1.0),
1031 PhysicalPosition::new(1, 2)
1032 );
1033 assert_eq!(
1034 PhysicalPosition::from_logical(LogicalPosition::new(2.0, 4.0), 0.5),
1035 PhysicalPosition::new(1, 2)
1036 );
1037 assert_eq!(PhysicalPosition::from((2.0, 2.0)), PhysicalPosition::new(2.0, 2.0));
1038 assert_eq!(PhysicalPosition::from([2.0, 3.0]), PhysicalPosition::new(2.0, 3.0));
1039
1040 let x: (f64, f64) = PhysicalPosition::new(1, 2).into();
1041 assert_eq!(x, (1.0, 2.0));
1042 let x: [f64; 2] = PhysicalPosition::new(1, 2).into();
1043 assert_eq!(x, [1.0, 2.0]);
1044 }
1045
1046 #[test]
1047 fn test_logical_size() {
1048 let log_size = LogicalSize::new(1.0, 2.0);
1049 assert_eq!(log_size.to_physical::<u32>(1.0), PhysicalSize::new(1, 2));
1050 assert_eq!(log_size.to_physical::<u32>(2.0), PhysicalSize::new(2, 4));
1051 assert_eq!(log_size.cast::<u32>(), LogicalSize::new(1, 2));
1052 assert_eq!(log_size, LogicalSize::from_physical(PhysicalSize::new(1.0, 2.0), 1.0));
1053 assert_eq!(log_size, LogicalSize::from_physical(PhysicalSize::new(2.0, 4.0), 2.0));
1054 assert_eq!(LogicalSize::from((2.0, 2.0)), LogicalSize::new(2.0, 2.0));
1055 assert_eq!(LogicalSize::from([2.0, 3.0]), LogicalSize::new(2.0, 3.0));
1056
1057 let x: (f64, f64) = log_size.into();
1058 assert_eq!(x, (1.0, 2.0));
1059 let x: [f64; 2] = log_size.into();
1060 assert_eq!(x, [1.0, 2.0]);
1061 }
1062
1063 #[test]
1064 fn test_physical_size() {
1065 assert_eq!(
1066 PhysicalSize::from_logical(LogicalSize::new(1.0, 2.0), 1.0),
1067 PhysicalSize::new(1, 2)
1068 );
1069 assert_eq!(
1070 PhysicalSize::from_logical(LogicalSize::new(2.0, 4.0), 0.5),
1071 PhysicalSize::new(1, 2)
1072 );
1073 assert_eq!(PhysicalSize::from((2.0, 2.0)), PhysicalSize::new(2.0, 2.0));
1074 assert_eq!(PhysicalSize::from([2.0, 3.0]), PhysicalSize::new(2.0, 3.0));
1075
1076 let x: (f64, f64) = PhysicalSize::new(1, 2).into();
1077 assert_eq!(x, (1.0, 2.0));
1078 let x: [f64; 2] = PhysicalSize::new(1, 2).into();
1079 assert_eq!(x, [1.0, 2.0]);
1080 }
1081
1082 #[test]
1083 fn test_size() {
1084 assert_eq!(Size::new(PhysicalSize::new(1, 2)), Size::Physical(PhysicalSize::new(1, 2)));
1085 assert_eq!(
1086 Size::new(LogicalSize::new(1.0, 2.0)),
1087 Size::Logical(LogicalSize::new(1.0, 2.0))
1088 );
1089
1090 assert_eq!(
1091 Size::new(PhysicalSize::new(1, 2)).to_logical::<f64>(1.0),
1092 LogicalSize::new(1.0, 2.0)
1093 );
1094 assert_eq!(
1095 Size::new(PhysicalSize::new(1, 2)).to_logical::<f64>(2.0),
1096 LogicalSize::new(0.5, 1.0)
1097 );
1098 assert_eq!(
1099 Size::new(LogicalSize::new(1.0, 2.0)).to_logical::<f64>(1.0),
1100 LogicalSize::new(1.0, 2.0)
1101 );
1102
1103 assert_eq!(
1104 Size::new(PhysicalSize::new(1, 2)).to_physical::<u32>(1.0),
1105 PhysicalSize::new(1, 2)
1106 );
1107 assert_eq!(
1108 Size::new(PhysicalSize::new(1, 2)).to_physical::<u32>(2.0),
1109 PhysicalSize::new(1, 2)
1110 );
1111 assert_eq!(
1112 Size::new(LogicalSize::new(1.0, 2.0)).to_physical::<u32>(1.0),
1113 PhysicalSize::new(1, 2)
1114 );
1115 assert_eq!(
1116 Size::new(LogicalSize::new(1.0, 2.0)).to_physical::<u32>(2.0),
1117 PhysicalSize::new(2, 4)
1118 );
1119
1120 let small = Size::Physical((1, 2).into());
1121 let medium = Size::Logical((3, 4).into());
1122 let medium_physical = Size::new(medium.to_physical::<u32>(1.0));
1123 let large = Size::Physical((5, 6).into());
1124 assert_eq!(Size::clamp(medium, small, large, 1.0), medium_physical);
1125 assert_eq!(Size::clamp(small, medium, large, 1.0), medium_physical);
1126 assert_eq!(Size::clamp(large, small, medium, 1.0), medium_physical);
1127 }
1128
1129 #[test]
1130 fn test_position() {
1131 assert_eq!(
1132 Position::new(PhysicalPosition::new(1, 2)),
1133 Position::Physical(PhysicalPosition::new(1, 2))
1134 );
1135 assert_eq!(
1136 Position::new(LogicalPosition::new(1.0, 2.0)),
1137 Position::Logical(LogicalPosition::new(1.0, 2.0))
1138 );
1139
1140 assert_eq!(
1141 Position::new(PhysicalPosition::new(1, 2)).to_logical::<f64>(1.0),
1142 LogicalPosition::new(1.0, 2.0)
1143 );
1144 assert_eq!(
1145 Position::new(PhysicalPosition::new(1, 2)).to_logical::<f64>(2.0),
1146 LogicalPosition::new(0.5, 1.0)
1147 );
1148 assert_eq!(
1149 Position::new(LogicalPosition::new(1.0, 2.0)).to_logical::<f64>(1.0),
1150 LogicalPosition::new(1.0, 2.0)
1151 );
1152
1153 assert_eq!(
1154 Position::new(PhysicalPosition::new(1, 2)).to_physical::<u32>(1.0),
1155 PhysicalPosition::new(1, 2)
1156 );
1157 assert_eq!(
1158 Position::new(PhysicalPosition::new(1, 2)).to_physical::<u32>(2.0),
1159 PhysicalPosition::new(1, 2)
1160 );
1161 assert_eq!(
1162 Position::new(LogicalPosition::new(1.0, 2.0)).to_physical::<u32>(1.0),
1163 PhysicalPosition::new(1, 2)
1164 );
1165 assert_eq!(
1166 Position::new(LogicalPosition::new(1.0, 2.0)).to_physical::<u32>(2.0),
1167 PhysicalPosition::new(2, 4)
1168 );
1169 }
1170
1171 #[test]
1173 fn ensure_attrs_do_not_panic() {
1174 let _ = std::format!("{:?}", LogicalPosition::<u32>::default().clone());
1175 HashSet::new().insert(LogicalPosition::<u32>::default());
1176
1177 let _ = std::format!("{:?}", PhysicalPosition::<u32>::default().clone());
1178 HashSet::new().insert(PhysicalPosition::<u32>::default());
1179
1180 let _ = std::format!("{:?}", LogicalSize::<u32>::default().clone());
1181 HashSet::new().insert(LogicalSize::<u32>::default());
1182
1183 let _ = std::format!("{:?}", PhysicalSize::<u32>::default().clone());
1184 HashSet::new().insert(PhysicalSize::<u32>::default());
1185
1186 let _ = std::format!("{:?}", Size::Physical((1, 2).into()).clone());
1187 let _ = std::format!("{:?}", Position::Physical((1, 2).into()).clone());
1188 }
1189
1190 #[test]
1191 fn ensure_copy_trait() {
1192 fn is_copy<T: Copy>() {}
1193
1194 is_copy::<LogicalUnit<i32>>();
1195 is_copy::<PhysicalUnit<f64>>();
1196 is_copy::<PixelUnit>();
1197
1198 is_copy::<LogicalSize<i32>>();
1199 is_copy::<PhysicalSize<f64>>();
1200 is_copy::<Size>();
1201
1202 is_copy::<LogicalPosition<i32>>();
1203 is_copy::<PhysicalPosition<f64>>();
1204 is_copy::<Position>();
1205 }
1206
1207 #[test]
1208 fn ensure_partial_eq_trait() {
1209 fn is_partial_eq<T: PartialEq>() {}
1210
1211 is_partial_eq::<LogicalUnit<i32>>();
1212 is_partial_eq::<PhysicalUnit<f64>>();
1213 is_partial_eq::<PixelUnit>();
1214
1215 is_partial_eq::<LogicalSize<i32>>();
1216 is_partial_eq::<PhysicalSize<f64>>();
1217 is_partial_eq::<Size>();
1218
1219 is_partial_eq::<LogicalPosition<i32>>();
1220 is_partial_eq::<PhysicalPosition<f64>>();
1221 is_partial_eq::<Position>();
1222 }
1223}