rust/integral-geometry/src/lib.rs
changeset 15828 44b49f255e31
parent 15751 a4558e2be08c
child 15918 9bd828451d77
child 15981 5ba4d3a0c3eb
--- a/rust/integral-geometry/src/lib.rs	Tue Jan 25 23:46:11 2022 +0300
+++ b/rust/integral-geometry/src/lib.rs	Thu Jan 27 03:51:13 2022 +0300
@@ -141,11 +141,16 @@
     }
 
     #[inline]
-    pub fn next_power_of_two(&self) -> Self {
-        Self {
-            width: self.width.next_power_of_two(),
-            height: self.height.next_power_of_two(),
-        }
+    pub const fn as_power_of_two(&self) -> Option<PotSize> {
+        PotSize::new(self.width, self.height)
+    }
+
+    #[inline]
+    pub const fn next_power_of_two(&self) -> PotSize {
+        PotSize::new_impl(
+            self.width.next_power_of_two(),
+            self.height.next_power_of_two(),
+        )
     }
 
     #[inline]
@@ -154,19 +159,10 @@
     }
 
     #[inline]
-    pub fn to_mask(&self) -> SizeMask {
-        SizeMask::new(*self)
-    }
-
-    #[inline]
     pub fn to_square(&self) -> Self {
         Self::square(max(self.width, self.height))
     }
 
-    pub fn to_grid_index(&self) -> GridIndex {
-        GridIndex::new(*self)
-    }
-
     #[inline]
     pub const fn contains(&self, other: Self) -> bool {
         self.width >= other.width && self.height >= other.height
@@ -174,11 +170,96 @@
 
     #[inline]
     pub fn join(&self, other: Self) -> Self {
+        Self::new(max(self.width, other.width), max(self.height, other.height))
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct PotSize {
+    size: Size,
+}
+
+impl PotSize {
+    #[inline]
+    const fn new_impl(width: usize, height: usize) -> Self {
+        debug_assert!(width.is_power_of_two() && height.is_power_of_two());
         Self {
-            width: max(self.width, other.width),
-            height: max(self.height, other.height)
+            size: Size::new(width, height),
+        }
+    }
+
+    #[inline]
+    pub const fn new(width: usize, height: usize) -> Option<Self> {
+        if width.is_power_of_two() && height.is_power_of_two() {
+            Some(Self::new_impl(width, height))
+        } else {
+            None
+        }
+    }
+
+    pub const fn size(&self) -> Size {
+        self.size
+    }
+
+    pub const fn width(&self) -> usize {
+        self.size.width
+    }
+
+    pub const fn height(&self) -> usize {
+        self.size.height
+    }
+
+    #[inline]
+    pub const fn square(size: usize) -> Option<Self> {
+        if size.is_power_of_two() {
+            Some(Self::new_impl(size, size))
+        } else {
+            None
         }
     }
+
+    #[inline]
+    pub const fn area(&self) -> usize {
+        self.size.area()
+    }
+
+    #[inline]
+    pub const fn linear_index(&self, x: usize, y: usize) -> usize {
+        self.size.linear_index(x, y)
+    }
+
+    #[inline]
+    pub const fn transpose(&self) -> Self {
+        Self::new_impl(self.height(), self.width())
+    }
+
+    #[inline]
+    pub fn to_square(&self) -> Self {
+        let size = max(self.width(), self.height());
+        Self::new_impl(size, size)
+    }
+
+    #[inline]
+    pub const fn to_mask(&self) -> SizeMask {
+        SizeMask::new(*self)
+    }
+
+    pub const fn to_grid_index(&self) -> GridIndex {
+        GridIndex::new(*self)
+    }
+
+    #[inline]
+    pub const fn contains(&self, other: Self) -> bool {
+        self.size.contains(other.size)
+    }
+
+    #[inline]
+    pub fn join(&self, other: Self) -> Self {
+        Self::new_impl(
+            max(self.width(), other.width()),
+            max(self.height(), other.height()),
+        )
+    }
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -188,13 +269,10 @@
 
 impl SizeMask {
     #[inline]
-    pub fn new(size: Size) -> Self {
-        debug_assert!(size.is_power_of_two());
-        let size = Size {
-            width: !(size.width - 1),
-            height: !(size.height - 1),
-        };
-        Self { size }
+    pub const fn new(size: PotSize) -> Self {
+        Self {
+            size: Size::new(!(size.width() - 1), !(size.height() - 1)),
+        }
     }
 
     #[inline]
@@ -211,6 +289,11 @@
     pub fn contains(&self, point: Point) -> bool {
         self.contains_x(point.x as usize) && self.contains_y(point.y as usize)
     }
+
+    #[inline]
+    pub const fn to_size(&self) -> PotSize {
+        PotSize::new_impl(!self.size.width + 1, !self.size.height + 1)
+    }
 }
 
 pub struct GridIndex {
@@ -218,11 +301,10 @@
 }
 
 impl GridIndex {
-    pub fn new(size: Size) -> Self {
-        debug_assert!(size.is_power_of_two());
+    pub const fn new(size: PotSize) -> Self {
         let shift = Point::new(
-            size.width.trailing_zeros() as i32,
-            size.height.trailing_zeros() as i32,
+            size.width().trailing_zeros() as i32,
+            size.height().trailing_zeros() as i32,
         );
         Self { shift }
     }
@@ -324,7 +406,7 @@
     };
 
     #[inline]
-    pub fn new(top_left: Point, bottom_right: Point) -> Self {
+    pub const fn new(top_left: Point, bottom_right: Point) -> Self {
         debug_assert!(top_left.x <= bottom_right.x + 1);
         debug_assert!(top_left.y <= bottom_right.y + 1);
         Self {
@@ -333,7 +415,7 @@
         }
     }
 
-    pub fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self {
+    pub const fn from_box(left: i32, right: i32, top: i32, bottom: i32) -> Self {
         Self::new(Point::new(left, top), Point::new(right, bottom))
     }
 
@@ -450,7 +532,7 @@
     }
 
     #[inline]
-    pub fn split_at(&self, point: Point) -> [Rect; 4] {
+    pub const fn split_at(&self, point: Point) -> [Rect; 4] {
         debug_assert!(self.contains_inside(point));
         [
             Self::from_box(self.left(), point.x, self.top(), point.y),
@@ -461,7 +543,7 @@
     }
 
     #[inline]
-    pub fn with_margins(&self, left: i32, right: i32, top: i32, bottom: i32) -> Self {
+    pub const fn with_margins(&self, left: i32, right: i32, top: i32, bottom: i32) -> Self {
         Self::from_box(
             self.left() - left,
             self.right() + right,