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