From c6c494e52e45c28ec04d8fbb953a26ac8555d7af Mon Sep 17 00:00:00 2001
From: Amr Bashir <amr.bashir2015@gmail.com>
Date: Fri, 7 Jul 2023 04:01:41 +0300
Subject: [PATCH] use macros to generate DPI types

ref: https://github.com/rust-windowing/winit/pull/2148
---
 examples/min_max_size.rs                |  14 +-
 src/dpi.rs                              | 707 ++++++++----------------
 src/platform_impl/windows/event_loop.rs |  10 +-
 src/window.rs                           |  50 +-
 4 files changed, 258 insertions(+), 523 deletions(-)

diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs
index 85894e5f8..527519727 100644
--- a/examples/min_max_size.rs
+++ b/examples/min_max_size.rs
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 use tao::{
-  dpi::LogicalUnit,
+  dpi::LogicalPixel,
   event::{ElementState, Event, KeyEvent, WindowEvent},
   event_loop::{ControlFlow, EventLoop},
   keyboard::Key,
@@ -53,22 +53,22 @@ fn main() {
       } => match key_str {
         "e" => {
           size_constraints.min_width =
-            (!size_constraints.min_width.is_some()).then_some(LogicalUnit::new(min_width).into());
+            (!size_constraints.min_width.is_some()).then_some(LogicalPixel::new(min_width).into());
           window.set_inner_size_constraints(size_constraints);
         }
         "f" => {
           size_constraints.max_width =
-            (!size_constraints.max_width.is_some()).then_some(LogicalUnit::new(max_width).into());
+            (!size_constraints.max_width.is_some()).then_some(LogicalPixel::new(max_width).into());
           window.set_inner_size_constraints(size_constraints);
         }
         "p" => {
-          size_constraints.min_height =
-            (!size_constraints.min_height.is_some()).then_some(LogicalUnit::new(min_height).into());
+          size_constraints.min_height = (!size_constraints.min_height.is_some())
+            .then_some(LogicalPixel::new(min_height).into());
           window.set_inner_size_constraints(size_constraints);
         }
         "v" => {
-          size_constraints.max_height =
-            (!size_constraints.max_height.is_some()).then_some(LogicalUnit::new(max_height).into());
+          size_constraints.max_height = (!size_constraints.max_height.is_some())
+            .then_some(LogicalPixel::new(max_height).into());
           window.set_inner_size_constraints(size_constraints);
         }
         _ => {}
diff --git a/src/dpi.rs b/src/dpi.rs
index dd2bb91a8..3b4fb4ae1 100644
--- a/src/dpi.rs
+++ b/src/dpi.rs
@@ -93,55 +93,70 @@
 
 pub trait Pixel: Copy + Into<f64> {
   fn from_f64(f: f64) -> Self;
-  fn inner(&self) -> Self {
-    *self
-  }
   fn cast<P: Pixel>(self) -> P {
     P::from_f64(self.into())
   }
 }
 
-impl Pixel for u8 {
-  fn from_f64(f: f64) -> Self {
-    f.round() as u8
-  }
-}
-impl Pixel for u16 {
-  fn from_f64(f: f64) -> Self {
-    f.round() as u16
-  }
-}
-impl Pixel for u32 {
-  fn from_f64(f: f64) -> Self {
-    f.round() as u32
-  }
-}
-impl Pixel for i8 {
-  fn from_f64(f: f64) -> Self {
-    f.round() as i8
-  }
-}
-impl Pixel for i16 {
-  fn from_f64(f: f64) -> Self {
-    f.round() as i16
-  }
-}
-impl Pixel for i32 {
-  fn from_f64(f: f64) -> Self {
-    f.round() as i32
-  }
+macro_rules! pixel_int_impl {
+  ($($t:ty),*) => {$(
+      impl Pixel for $t {
+          fn from_f64(f: f64) -> Self {
+              f.round() as $t
+          }
+      }
+  )*}
 }
+
+pixel_int_impl!(u8, u16, u32, i8, i16, i32);
+
 impl Pixel for f32 {
   fn from_f64(f: f64) -> Self {
     f as f32
   }
 }
+
 impl Pixel for f64 {
   fn from_f64(f: f64) -> Self {
     f
   }
 }
 
+macro_rules! from_impls {
+  ($t:ident, $a:ident, $(,)? ) => {
+    impl<P: Pixel> From<P> for $t<P> {
+      fn from($a: P) -> Self {
+        Self::new($a.cast())
+      }
+    }
+  };
+  ($t:ident, $a:ident, $b:ident$(,)? ) => {
+    impl<P: Pixel, X: Pixel> From<(X, X)> for $t<P> {
+      fn from(($a, $b): (X, X)) -> Self {
+        Self::new($a.cast(), $b.cast())
+      }
+    }
+
+    impl<P: Pixel, X: Pixel> From<$t<P>> for (X, X) {
+      fn from(p: $t<P>) -> Self {
+        (p.$a.cast(), p.$b.cast())
+      }
+    }
+
+    impl<P: Pixel, X: Pixel> From<[X; 2]> for $t<P> {
+      fn from([$a, $b]: [X; 2]) -> Self {
+        Self::new($a.cast(), $b.cast())
+      }
+    }
+
+    impl<P: Pixel, X: Pixel> From<$t<P>> for [X; 2] {
+      fn from(p: $t<P>) -> Self {
+        [p.$a.cast(), p.$b.cast()]
+      }
+    }
+  };
+}
+
 /// Checks that the scale factor is a normal positive `f64`.
 ///
 /// All functions that take a scale factor assert that this will return `true`. If you're sourcing scale factors from
@@ -152,349 +167,213 @@ pub fn validate_scale_factor(scale_factor: f64) -> bool {
   scale_factor.is_sign_positive() && scale_factor.is_normal()
 }
 
-/// A position represented in logical pixels.
-///
-/// The position is stored as floats, so please be careful. Casting floats to integers truncates the
-/// fractional part, which can cause noticeable issues. To help with that, an `Into<(i32, i32)>`
-/// implementation is provided which does the rounding for you.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct LogicalPosition<P> {
-  pub x: P,
-  pub y: P,
-}
-
-impl<P> LogicalPosition<P> {
-  #[inline]
-  pub const fn new(x: P, y: P) -> Self {
-    LogicalPosition { x, y }
-  }
-}
-
-impl<P: Pixel> LogicalPosition<P> {
-  #[inline]
-  pub fn from_physical<T: Into<PhysicalPosition<X>>, X: Pixel>(
-    physical: T,
-    scale_factor: f64,
-  ) -> Self {
-    physical.into().to_logical(scale_factor)
-  }
-
-  #[inline]
-  pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<X> {
-    assert!(validate_scale_factor(scale_factor));
-    let x = self.x.into() * scale_factor;
-    let y = self.y.into() * scale_factor;
-    PhysicalPosition::new(x, y).cast()
-  }
-
-  #[inline]
-  pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> {
-    LogicalPosition {
-      x: self.x.cast(),
-      y: self.y.cast(),
-    }
-  }
-}
-
-impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalPosition<P> {
-  fn from((x, y): (X, X)) -> LogicalPosition<P> {
-    LogicalPosition::new(x.cast(), y.cast())
-  }
-}
-
-impl<P: Pixel, X: Pixel> Into<(X, X)> for LogicalPosition<P> {
-  fn into(self) -> (X, X) {
-    (self.x.cast(), self.y.cast())
-  }
-}
-
-impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalPosition<P> {
-  fn from([x, y]: [X; 2]) -> LogicalPosition<P> {
-    LogicalPosition::new(x.cast(), y.cast())
-  }
-}
-
-impl<P: Pixel, X: Pixel> Into<[X; 2]> for LogicalPosition<P> {
-  fn into(self) -> [X; 2] {
-    [self.x.cast(), self.y.cast()]
-  }
-}
-
-/// A position represented in physical pixels.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct PhysicalPosition<P> {
-  pub x: P,
-  pub y: P,
-}
-
-impl<P> PhysicalPosition<P> {
-  #[inline]
-  pub const fn new(x: P, y: P) -> Self {
-    PhysicalPosition { x, y }
-  }
-}
-
-impl<P: Pixel> PhysicalPosition<P> {
-  #[inline]
-  pub fn from_logical<T: Into<LogicalPosition<X>>, X: Pixel>(
-    logical: T,
-    scale_factor: f64,
-  ) -> Self {
-    logical.into().to_physical(scale_factor)
-  }
-
-  #[inline]
-  pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalPosition<X> {
-    assert!(validate_scale_factor(scale_factor));
-    let x = self.x.into() / scale_factor;
-    let y = self.y.into() / scale_factor;
-    LogicalPosition::new(x, y).cast()
-  }
-
-  #[inline]
-  pub fn cast<X: Pixel>(&self) -> PhysicalPosition<X> {
-    PhysicalPosition {
-      x: self.x.cast(),
-      y: self.y.cast(),
-    }
-  }
-}
-
-impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalPosition<P> {
-  fn from((x, y): (X, X)) -> PhysicalPosition<P> {
-    PhysicalPosition::new(x.cast(), y.cast())
-  }
-}
-
-impl<P: Pixel, X: Pixel> Into<(X, X)> for PhysicalPosition<P> {
-  fn into(self) -> (X, X) {
-    (self.x.cast(), self.y.cast())
-  }
-}
+macro_rules! dpi_type {
+  (
+      $(let $a:ident;)*
 
-impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalPosition<P> {
-  fn from([x, y]: [X; 2]) -> PhysicalPosition<P> {
-    PhysicalPosition::new(x.cast(), y.cast())
-  }
-}
-
-impl<P: Pixel, X: Pixel> Into<[X; 2]> for PhysicalPosition<P> {
-  fn into(self) -> [X; 2] {
-    [self.x.cast(), self.y.cast()]
-  }
-}
-
-/// A position that's either physical or logical.
-#[non_exhaustive]
-#[derive(Debug, Copy, Clone, PartialEq)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub enum Position {
-  Physical(PhysicalPosition<i32>),
-  Logical(LogicalPosition<f64>),
-}
-
-impl Position {
-  pub fn new<S: Into<Position>>(position: S) -> Position {
-    position.into()
-  }
+      $(#[$logical_meta:meta])*
+      pub struct $LogicalType:ident;
+      $(#[$physical_meta:meta])*
+      pub struct $PhysicalType:ident;
+      $(#[$unified_meta:meta])*
+      pub enum $UnifiedType:ident {
+          Physical($unified_physical:ty),
+          Logical($unified_logical:ty),
+      }
+  ) => {
+      $(#[$logical_meta])*
+      #[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)]
+      #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+      pub struct $LogicalType<P> {
+          $(pub $a: P,)*
+      }
 
-  pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalPosition<P> {
-    match *self {
-      Position::Physical(position) => position.to_logical(scale_factor),
-      Position::Logical(position) => position.cast(),
-    }
-  }
+      impl<P> $LogicalType<P> {
+          #[inline]
+          pub const fn new($($a: P,)*) -> Self {
+              $LogicalType { $($a,)* }
+          }
+      }
 
-  pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<P> {
-    match *self {
-      Position::Physical(position) => position.cast(),
-      Position::Logical(position) => position.to_physical(scale_factor),
-    }
-  }
-}
+      impl<P: Pixel> $LogicalType<P> {
+          #[inline]
+          pub fn from_physical<T: Into<$PhysicalType<X>>, X: Pixel>(
+              physical: T,
+              scale_factor: f64,
+          ) -> Self {
+              physical.into().to_logical(scale_factor)
+          }
+
+          #[inline]
+          pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> $PhysicalType<X> {
+              assert!(validate_scale_factor(scale_factor));
+              $(let $a = self.$a.into() * scale_factor;)*
+              $PhysicalType::new($($a,)*).cast()
+          }
+
+          #[inline]
+          pub fn cast<X: Pixel>(&self) -> $LogicalType<X> {
+              $LogicalType {
+                  $($a: self.$a.cast(),)*
+              }
+          }
+      }
 
-impl<P: Pixel> From<PhysicalPosition<P>> for Position {
-  #[inline]
-  fn from(position: PhysicalPosition<P>) -> Position {
-    Position::Physical(position.cast())
-  }
-}
+      from_impls!($LogicalType, $($a,)*);
 
-impl<P: Pixel> From<LogicalPosition<P>> for Position {
-  #[inline]
-  fn from(position: LogicalPosition<P>) -> Position {
-    Position::Logical(position.cast())
-  }
-}
+      $(#[$physical_meta])*
+      #[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)]
+      #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+      pub struct $PhysicalType<P> {
+        $(pub $a: P,)*
+      }
 
-/// A size represented in logical pixels.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct LogicalSize<P> {
-  pub width: P,
-  pub height: P,
-}
+      impl<P> $PhysicalType<P> {
+          #[inline]
+          pub const fn new($($a: P,)*) -> Self {
+              $PhysicalType { $($a,)* }
+          }
+      }
 
-impl<P> LogicalSize<P> {
-  #[inline]
-  pub const fn new(width: P, height: P) -> Self {
-    LogicalSize { width, height }
-  }
-}
+      impl<P: Pixel> $PhysicalType<P> {
+          #[inline]
+          pub fn from_logical<T: Into<$LogicalType<X>>, X: Pixel>(
+              logical: T,
+              scale_factor: f64,
+          ) -> Self {
+              logical.into().to_physical(scale_factor)
+          }
+
+          #[inline]
+          pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> $LogicalType<X> {
+              assert!(validate_scale_factor(scale_factor));
+              $(let $a = self.$a.into() / scale_factor;)*
+              $LogicalType::new($($a,)*).cast()
+          }
+
+          #[inline]
+          pub fn cast<X: Pixel>(&self) -> $PhysicalType<X> {
+              $PhysicalType {
+                  $($a: self.$a.cast(),)*
+              }
+          }
+      }
 
-impl<P: Pixel> LogicalSize<P> {
-  #[inline]
-  pub fn from_physical<T: Into<PhysicalSize<X>>, X: Pixel>(physical: T, scale_factor: f64) -> Self {
-    physical.into().to_logical(scale_factor)
-  }
+      from_impls!($PhysicalType, $($a,)*);
 
-  #[inline]
-  pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalSize<X> {
-    assert!(validate_scale_factor(scale_factor));
-    let width = self.width.into() * scale_factor;
-    let height = self.height.into() * scale_factor;
-    PhysicalSize::new(width, height).cast()
-  }
+      $(#[$unified_meta])*
+      #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
+      #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+      pub enum $UnifiedType {
+          Physical($unified_physical),
+          Logical($unified_logical),
+      }
 
-  #[inline]
-  pub fn cast<X: Pixel>(&self) -> LogicalSize<X> {
-    LogicalSize {
-      width: self.width.cast(),
-      height: self.height.cast(),
-    }
-  }
-}
+      impl $UnifiedType {
+          pub fn new<S: Into<$UnifiedType>>(val: S) -> $UnifiedType {
+              val.into()
+          }
+
+          pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> $LogicalType<P> {
+              match *self {
+                  $UnifiedType::Physical(val) => val.to_logical(scale_factor),
+                  $UnifiedType::Logical(val) => val.cast(),
+              }
+          }
+
+          pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> $PhysicalType<P> {
+              match *self {
+                  $UnifiedType::Physical(val) => val.cast(),
+                  $UnifiedType::Logical(val) => val.to_physical(scale_factor),
+              }
+          }
+
+          $(pub fn $a(&self) -> PixelUnit {
+            match *self {
+              $UnifiedType::Physical(any) => PixelUnit::Physical(any.$a.into()),
+              $UnifiedType::Logical(any) => PixelUnit::Logical(any.$a.into()),
+            }
+          })*
+      }
 
-impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalSize<P> {
-  fn from((x, y): (X, X)) -> LogicalSize<P> {
-    LogicalSize::new(x.cast(), y.cast())
-  }
-}
+      impl<P: Pixel> From<$PhysicalType<P>> for $UnifiedType {
+          #[inline]
+          fn from(val: $PhysicalType<P>) -> $UnifiedType {
+              $UnifiedType::Physical(val.cast())
+          }
+      }
 
-impl<P: Pixel, X: Pixel> Into<(X, X)> for LogicalSize<P> {
-  fn into(self: LogicalSize<P>) -> (X, X) {
-    (self.width.cast(), self.height.cast())
-  }
+      impl<P: Pixel> From<$LogicalType<P>> for $UnifiedType {
+          #[inline]
+          fn from(val: $LogicalType<P>) -> $UnifiedType {
+              $UnifiedType::Logical(val.cast())
+          }
+      }
+  };
 }
 
-impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalSize<P> {
-  fn from([x, y]: [X; 2]) -> LogicalSize<P> {
-    LogicalSize::new(x.cast(), y.cast())
-  }
-}
+dpi_type! {
+  let value;
 
-impl<P: Pixel, X: Pixel> Into<[X; 2]> for LogicalSize<P> {
-  fn into(self) -> [X; 2] {
-    [self.width.cast(), self.height.cast()]
+  /// A logical pixel.
+  pub struct LogicalPixel;
+  /// A physical pixel.
+  pub struct PhysicalPixel;
+  /// A pixel that's either physical or logical.
+  pub enum PixelUnit {
+      Physical(PhysicalPixel<i32>),
+      Logical(LogicalPixel<f64>),
   }
 }
 
-/// A size represented in physical pixels.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct PhysicalSize<P> {
-  pub width: P,
-  pub height: P,
+impl PixelUnit {
+  /// Represents a minimum logical unit of `0`
+  pub const MIN: PixelUnit = PixelUnit::Logical(LogicalPixel::new(0.0));
+  /// Represents a maximum logical unit that is equal to [`f64::MAX`]
+  pub const MAX: PixelUnit = PixelUnit::Logical(LogicalPixel::new(f64::MAX));
 }
 
-impl<P> PhysicalSize<P> {
-  #[inline]
-  pub const fn new(width: P, height: P) -> Self {
-    PhysicalSize { width, height }
-  }
-}
-
-impl<P: Pixel> PhysicalSize<P> {
-  #[inline]
-  pub fn from_logical<T: Into<LogicalSize<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
-    logical.into().to_physical(scale_factor)
-  }
-
-  #[inline]
-  pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalSize<X> {
-    assert!(validate_scale_factor(scale_factor));
-    let width = self.width.into() / scale_factor;
-    let height = self.height.into() / scale_factor;
-    LogicalSize::new(width, height).cast()
-  }
-
-  #[inline]
-  pub fn cast<X: Pixel>(&self) -> PhysicalSize<X> {
-    PhysicalSize {
-      width: self.width.cast(),
-      height: self.height.cast(),
-    }
+impl From<u32> for PhysicalPixel<i32> {
+  fn from(value: u32) -> Self {
+    Self::new(value.cast())
   }
 }
 
-impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalSize<P> {
-  fn from((x, y): (X, X)) -> PhysicalSize<P> {
-    PhysicalSize::new(x.cast(), y.cast())
-  }
-}
+dpi_type! {
+  let x;
+  let y;
 
-impl<P: Pixel, X: Pixel> Into<(X, X)> for PhysicalSize<P> {
-  fn into(self) -> (X, X) {
-    (self.width.cast(), self.height.cast())
+  /// A position represented in logical pixels.
+  ///
+  /// The position is stored as floats, so please be careful. Casting floats to integers truncates the
+  /// fractional part, which can cause noticable issues. To help with that, an `Into<(i32, i32)>`
+  /// implementation is provided which does the rounding for you.
+  pub struct LogicalPosition;
+  /// A position represented in physical pixels.
+  pub struct PhysicalPosition;
+  /// A position that's either physical or logical.
+  pub enum Position {
+      Physical(PhysicalPosition<i32>),
+      Logical(LogicalPosition<f64>),
   }
 }
 
-impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalSize<P> {
-  fn from([x, y]: [X; 2]) -> PhysicalSize<P> {
-    PhysicalSize::new(x.cast(), y.cast())
-  }
-}
+dpi_type! {
+  let width;
+  let height;
 
-impl<P: Pixel, X: Pixel> Into<[X; 2]> for PhysicalSize<P> {
-  fn into(self) -> [X; 2] {
-    [self.width.cast(), self.height.cast()]
+  /// A size represented in logical pixels.
+  pub struct LogicalSize;
+  /// A size represented in physical pixels.
+  pub struct PhysicalSize;
+  /// A size that's either physical or logical.
+  pub enum Size {
+      Physical(PhysicalSize<u32>),
+      Logical(LogicalSize<f64>),
   }
 }
 
-/// A size that's either physical or logical.
-#[non_exhaustive]
-#[derive(Debug, Copy, Clone, PartialEq)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub enum Size {
-  Physical(PhysicalSize<u32>),
-  Logical(LogicalSize<f64>),
-}
-
 impl Size {
-  pub fn new<S: Into<Size>>(size: S) -> Size {
-    size.into()
-  }
-
-  pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalSize<P> {
-    match *self {
-      Size::Physical(size) => size.to_logical(scale_factor),
-      Size::Logical(size) => size.cast(),
-    }
-  }
-
-  pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalSize<P> {
-    match *self {
-      Size::Physical(size) => size.cast(),
-      Size::Logical(size) => size.to_physical(scale_factor),
-    }
-  }
-
-  pub fn width(&self) -> Unit {
-    match *self {
-      Size::Physical(size) => Unit::Physical(size.width.into()),
-      Size::Logical(size) => Unit::Logical(size.width.into()),
-    }
-  }
-
-  pub fn height(&self) -> Unit {
-    match *self {
-      Size::Physical(size) => Unit::Physical(size.height.into()),
-      Size::Logical(size) => Unit::Logical(size.height.into()),
-    }
-  }
-
   pub fn clamp<S: Into<Size>>(desired_size: S, min: S, max: S, scale_factor: f64) -> Size {
     let (desired_size, min, max) = (
       desired_size.into().to_physical::<f64>(scale_factor),
@@ -518,145 +397,3 @@ impl Size {
     PhysicalSize::new(width, height).into()
   }
 }
-
-impl<P: Pixel> From<PhysicalSize<P>> for Size {
-  #[inline]
-  fn from(size: PhysicalSize<P>) -> Size {
-    Size::Physical(size.cast())
-  }
-}
-
-impl<P: Pixel> From<LogicalSize<P>> for Size {
-  #[inline]
-  fn from(size: LogicalSize<P>) -> Size {
-    Size::Logical(size.cast())
-  }
-}
-
-/// A unit represented in logical pixels.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct LogicalUnit<P> {
-  pub value: P,
-}
-
-impl<P> LogicalUnit<P> {
-  #[inline]
-  pub const fn new(value: P) -> Self {
-    Self { value }
-  }
-}
-
-impl<P: Pixel> LogicalUnit<P> {
-  #[inline]
-  pub fn from_physical<T: Into<PhysicalUnit<X>>, X: Pixel>(physical: T, scale_factor: f64) -> Self {
-    physical.into().to_logical(scale_factor)
-  }
-
-  #[inline]
-  pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<X> {
-    assert!(validate_scale_factor(scale_factor));
-    let u = self.value.into() * scale_factor;
-    PhysicalUnit::new(u).cast()
-  }
-
-  #[inline]
-  pub fn cast<X: Pixel>(&self) -> LogicalUnit<X> {
-    LogicalUnit::new(self.value.cast())
-  }
-}
-
-impl<P: Pixel> From<P> for LogicalUnit<P> {
-  fn from(p: P) -> LogicalUnit<P> {
-    LogicalUnit::new(p.cast())
-  }
-}
-
-/// A unit represented in physical pixels.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct PhysicalUnit<P> {
-  pub value: P,
-}
-
-impl<P> PhysicalUnit<P> {
-  #[inline]
-  pub const fn new(value: P) -> Self {
-    Self { value }
-  }
-}
-
-impl<P: Pixel> PhysicalUnit<P> {
-  #[inline]
-  pub fn from_logical<T: Into<LogicalUnit<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
-    logical.into().to_physical(scale_factor)
-  }
-
-  #[inline]
-  pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalUnit<X> {
-    assert!(validate_scale_factor(scale_factor));
-    let u = self.value.into() / scale_factor;
-    LogicalUnit::new(u).cast()
-  }
-
-  #[inline]
-  pub fn cast<X: Pixel>(&self) -> PhysicalUnit<X> {
-    PhysicalUnit::new(self.value.cast())
-  }
-}
-
-impl<P: Pixel> From<P> for PhysicalUnit<P> {
-  fn from(p: P) -> PhysicalUnit<P> {
-    PhysicalUnit::new(p.cast())
-  }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub enum Unit {
-  Physical(PhysicalUnit<u32>),
-  Logical(LogicalUnit<f64>),
-}
-
-impl Default for Unit {
-  fn default() -> Self {
-    Self::Logical(LogicalUnit::new(f64::default()))
-  }
-}
-
-impl Unit {
-  pub const MIN: Unit = Unit::Logical(LogicalUnit::new(0.0));
-  pub const MAX: Unit = Unit::Logical(LogicalUnit::new(f64::MAX));
-
-  pub fn new<S: Into<Unit>>(val: S) -> Unit {
-    val.into()
-  }
-
-  pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalUnit<P> {
-    match *self {
-      Unit::Physical(val) => val.to_logical(scale_factor),
-      Unit::Logical(val) => val.cast(),
-    }
-  }
-
-  pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<P> {
-    match *self {
-      Unit::Physical(val) => val.cast(),
-      Unit::Logical(val) => val.to_physical(scale_factor),
-    }
-  }
-}
-
-impl<P: Pixel> From<PhysicalUnit<P>> for Unit {
-  #[inline]
-  fn from(val: PhysicalUnit<P>) -> Unit {
-    Unit::Physical(val.cast())
-  }
-}
-
-impl<P: Pixel> From<LogicalUnit<P>> for Unit {
-  #[inline]
-  fn from(val: LogicalUnit<P>) -> Unit {
-    Unit::Logical(val.cast())
-  }
-}
diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs
index c2e623b4c..126c33afb 100644
--- a/src/platform_impl/windows/event_loop.rs
+++ b/src/platform_impl/windows/event_loop.rs
@@ -44,7 +44,7 @@ use windows::{
 
 use crate::{
   accelerator::AcceleratorId,
-  dpi::{PhysicalPosition, PhysicalSize, Unit},
+  dpi::{PhysicalPosition, PhysicalSize, PixelUnit},
   error::ExternalError,
   event::{DeviceEvent, Event, Force, RawKeyEvent, Touch, TouchPhase, WindowEvent},
   event_loop::{ControlFlow, DeviceEventFilter, EventLoopClosed, EventLoopWindowTarget as RootELW},
@@ -1789,17 +1789,17 @@ unsafe fn public_window_callback_inner<T: 'static>(
       }
       if size_constraints.has_max() {
         // we can't use WindowSizeConstraints::max_size_physical because
-        // for Windows, in order to remove the max constraints, we need to fall to Unit::MIN (which is `0`)
-        // instead of Unit::MAX (which is f64::MAX)
+        // for Windows, in order to remove the max constraints, we need to fall to PixelUnit::MIN (which is `0`)
+        // instead of PixelUnit::MAX (which is f64::MAX)
         let max_size = PhysicalSize::new(
           size_constraints
             .max_width
-            .unwrap_or(Unit::MIN)
+            .unwrap_or(PixelUnit::MIN)
             .to_physical(window_state.scale_factor)
             .value,
           size_constraints
             .max_height
-            .unwrap_or(Unit::MIN)
+            .unwrap_or(PixelUnit::MIN)
             .to_physical(window_state.scale_factor)
             .value,
         );
diff --git a/src/window.rs b/src/window.rs
index 4d7a70946..b59782797 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -8,7 +8,7 @@ use std::fmt;
 use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle};
 
 use crate::{
-  dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size, Unit},
+  dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Pixel, PixelUnit, Position, Size},
   error::{ExternalError, NotSupportedError, OsError},
   event_loop::EventLoopWindowTarget,
   menu::MenuBar,
@@ -1418,27 +1418,27 @@ pub struct WindowSizeConstraints {
   /// The minimum width a window can be, If this is `None`, the window will have no minimum width (aside from reserved).
   ///
   /// The default is `None`.
-  pub min_width: Option<Unit>,
+  pub min_width: Option<PixelUnit>,
   /// The minimum height a window can be, If this is `None`, the window will have no minimum height (aside from reserved).
   ///
   /// The default is `None`.
-  pub min_height: Option<Unit>,
+  pub min_height: Option<PixelUnit>,
   /// The maximum width a window can be, If this is `None`, the window will have no maximum width (aside from reserved).
   ///
   /// The default is `None`.
-  pub max_width: Option<Unit>,
+  pub max_width: Option<PixelUnit>,
   /// The maximum height a window can be, If this is `None`, the window will have no maximum height (aside from reserved).
   ///
   /// The default is `None`.
-  pub max_height: Option<Unit>,
+  pub max_height: Option<PixelUnit>,
 }
 
 impl WindowSizeConstraints {
   pub fn new(
-    min_width: Option<Unit>,
-    min_height: Option<Unit>,
-    max_width: Option<Unit>,
-    max_height: Option<Unit>,
+    min_width: Option<PixelUnit>,
+    min_height: Option<PixelUnit>,
+    max_width: Option<PixelUnit>,
+    max_height: Option<PixelUnit>,
   ) -> Self {
     Self {
       min_width,
@@ -1448,82 +1448,80 @@ impl WindowSizeConstraints {
     }
   }
 
-  pub fn symmetrical(min: Option<Size>, max: Option<Size>) -> Self {
-    Self {
-      min_width: min.map(|s| s.width()),
-      min_height: min.map(|s| s.height()),
-      max_width: max.map(|s| s.width()),
-      max_height: max.map(|s| s.height()),
-    }
-  }
-
+  /// Returns true if `min_width` or `min_height` is set.
   pub fn has_min(&self) -> bool {
     self.min_width.is_some() || self.min_height.is_some()
   }
+  /// Returns true if `max_width` or `max_height` is set.
   pub fn has_max(&self) -> bool {
     self.max_width.is_some() || self.max_height.is_some()
   }
 
+  /// Returns a physical size that represents the minimum constraints set and fallbacks to [`PixelUnit::MIN`] for unset values
   pub fn min_size_physical<T: Pixel>(&self, scale_factor: f64) -> PhysicalSize<T> {
     PhysicalSize::new(
       self
         .min_width
-        .unwrap_or_default()
+        .unwrap_or(PixelUnit::MIN)
         .to_physical(scale_factor)
         .value,
       self
         .min_height
-        .unwrap_or_default()
+        .unwrap_or(PixelUnit::MIN)
         .to_physical(scale_factor)
         .value,
     )
   }
 
+  /// Returns a logical size that represents the minimum constraints set and fallbacks to [`PixelUnit::MIN`] for unset values
   pub fn min_size_logical<T: Pixel>(&self, scale_factor: f64) -> LogicalSize<T> {
     LogicalSize::new(
       self
         .min_width
-        .unwrap_or_default()
+        .unwrap_or(PixelUnit::MIN)
         .to_logical(scale_factor)
         .value,
       self
         .min_height
-        .unwrap_or_default()
+        .unwrap_or(PixelUnit::MIN)
         .to_logical(scale_factor)
         .value,
     )
   }
 
+  /// Returns a physical size that represents the maximum constraints set and fallbacks to [`PixelUnit::MAX`] for unset values
   pub fn max_size_physical<T: Pixel>(&self, scale_factor: f64) -> PhysicalSize<T> {
     PhysicalSize::new(
       self
         .max_width
-        .unwrap_or(Unit::MAX)
+        .unwrap_or(PixelUnit::MAX)
         .to_physical(scale_factor)
         .value,
       self
         .max_height
-        .unwrap_or(Unit::MAX)
+        .unwrap_or(PixelUnit::MAX)
         .to_physical(scale_factor)
         .value,
     )
   }
 
+  /// Returns a logical size that represents the maximum constraints set and fallbacks to [`PixelUnit::MAX`] for unset values
   pub fn max_size_logical<T: Pixel>(&self, scale_factor: f64) -> LogicalSize<T> {
     LogicalSize::new(
       self
         .max_width
-        .unwrap_or(Unit::MAX)
+        .unwrap_or(PixelUnit::MAX)
         .to_logical(scale_factor)
         .value,
       self
         .max_height
-        .unwrap_or(Unit::MAX)
+        .unwrap_or(PixelUnit::MAX)
         .to_logical(scale_factor)
         .value,
     )
   }
 
+  /// Clamps the desired size based on the constraints set
   pub fn clamp(&self, desired_size: Size, scale_factor: f64) -> Size {
     let min_size: PhysicalSize<f64> = self.min_size_physical(scale_factor);
     let max_size: PhysicalSize<f64> = self.max_size_physical(scale_factor);