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