Repository: ManevilleF/hexx (rust)

Issue:
Product impl always return 0
If we have an iterator of `Hex` called `hex_iter` then:
```rust
hex_iter.product()
```
will always return `Hex::ZERO`

Pull request description:
Feat/extra operations
> Closes #39 

## Fix

* Fixed `Product` impl for `Hex` which is always returning (0, 0) #39 

## Additions

* Added `Hex::min` method
* Added `Hex::max` method
* Added `Hex::signum` method
* Added `Hex::dot` method
* Added `Hex::from_slice` method
* Added `Hex::write_to_slice` method
* Added `Hex::dot` method

## Impls

* Added `BitOr` implementations for `Hex`
* Added `BitXor` implementations for `Hex`
* Added `BitAnd` implementations for `Hex`
* Added `Shr` implementations for `Hex`
* Added `Shl` implementations for `Hex`

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 472d0f0..ac0190b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,29 @@
 # CHANGELOG
 
+## Unreleased
+
+### Fix
+
+* Fixed `Product` impl for `Hex` which is always returning (0, 0)
+
+### Additions
+
+* Added `Hex::min` method
+* Added `Hex::max` method
+* Added `Hex::signum` method
+* Added `Hex::dot` method
+* Added `Hex::from_slice` method
+* Added `Hex::write_to_slice` method
+* Added `Hex::dot` method
+
+### Impls
+
+* Added `BitOr` implementations for `Hex`
+* Added `BitXor` implementations for `Hex`
+* Added `BitAnd` implementations for `Hex`
+* Added `Shr` implementations for `Hex`
+* Added `Shl` implementations for `Hex`
+
 ## 0.4.0 
 
 ### Directions
diff --git a/src/hex/impls.rs b/src/hex/impls.rs
index 5444991..e859d49 100644
--- a/src/hex/impls.rs
+++ b/src/hex/impls.rs
@@ -1,7 +1,10 @@
 use super::Hex;
 use std::{
     iter::{Product, Sum},
-    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
+    ops::{
+        Add, AddAssign, BitAnd, BitOr, BitXor, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign,
+        Shl, Shr, Sub, SubAssign,
+    },
 };
 
 impl Add<Self> for Hex {
@@ -19,8 +22,8 @@ impl Add<i32> for Hex {
     #[inline]
     fn add(self, rhs: i32) -> Self::Output {
         Self {
-            x: self.x + rhs,
-            y: self.y + rhs,
+            x: self.x.add(rhs),
+            y: self.y.add(rhs),
         }
     }
 }
@@ -28,26 +31,26 @@ impl Add<i32> for Hex {
 impl AddAssign for Hex {
     #[inline]
     fn add_assign(&mut self, rhs: Self) {
-        *self = *self + rhs;
+        *self = self.add(rhs);
     }
 }
 
 impl AddAssign<i32> for Hex {
     #[inline]
     fn add_assign(&mut self, rhs: i32) {
-        *self = *self + rhs;
+        *self = self.add(rhs);
     }
 }
 
 impl Sum for Hex {
     fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
-        iter.fold(Self::ZERO, |a, b| a + b)
+        iter.fold(Self::ZERO, Self::const_add)
     }
 }
 
 impl<'a> Sum<&'a Self> for Hex {
     fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
-        iter.copied().sum()
+        iter.fold(Self::ZERO, |a, &b| Self::const_add(a, b))
     }
 }
 
@@ -66,8 +69,8 @@ impl Sub<i32> for Hex {
     #[inline]
     fn sub(self, rhs: i32) -> Self::Output {
         Self {
-            x: self.x - rhs,
-            y: self.y - rhs,
+            x: self.x.sub(rhs),
+            y: self.y.sub(rhs),
         }
     }
 }
@@ -75,14 +78,14 @@ impl Sub<i32> for Hex {
 impl SubAssign for Hex {
     #[inline]
     fn sub_assign(&mut self, rhs: Self) {
-        *self = *self - rhs;
+        *self = self.sub(rhs);
     }
 }
 
 impl SubAssign<i32> for Hex {
     #[inline]
     fn sub_assign(&mut self, rhs: i32) {
-        *self = *self - rhs;
+        *self = self.sub(rhs);
     }
 }
 
@@ -92,8 +95,8 @@ impl Mul<Self> for Hex {
     #[inline]
     fn mul(self, rhs: Self) -> Self::Output {
         Self {
-            x: self.x * rhs.x,
-            y: self.y * rhs.y,
+            x: self.x.mul(rhs.x),
+            y: self.y.mul(rhs.y),
         }
     }
 }
@@ -104,8 +107,8 @@ impl Mul<i32> for Hex {
     #[inline]
     fn mul(self, rhs: i32) -> Self::Output {
         Self {
-            x: self.x * rhs,
-            y: self.y * rhs,
+            x: self.x.mul(rhs),
+            y: self.y.mul(rhs),
         }
     }
 }
@@ -123,33 +126,33 @@ impl Mul<f32> for Hex {
 impl MulAssign for Hex {
     #[inline]
     fn mul_assign(&mut self, rhs: Self) {
-        *self = *self * rhs;
+        *self = self.mul(rhs);
     }
 }
 
 impl MulAssign<i32> for Hex {
     #[inline]
     fn mul_assign(&mut self, rhs: i32) {
-        *self = *self * rhs;
+        *self = self.mul(rhs);
     }
 }
 
 impl MulAssign<f32> for Hex {
     #[inline]
     fn mul_assign(&mut self, rhs: f32) {
-        *self = *self * rhs;
+        *self = self.mul(rhs);
     }
 }
 
 impl Product for Hex {
     fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
-        iter.fold(Self::ZERO, |a, b| a * b)
+        iter.fold(Self::ONE, Self::mul)
     }
 }
 
 impl<'a> Product<&'a Self> for Hex {
     fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
-        iter.copied().product()
+        iter.fold(Self::ONE, |a, &b| Self::mul(a, b))
     }
 }
 
@@ -159,8 +162,8 @@ impl Div<Self> for Hex {
     #[inline]
     fn div(self, rhs: Self) -> Self::Output {
         Self {
-            x: self.x / rhs.x,
-            y: self.y / rhs.y,
+            x: self.x.div(rhs.x),
+            y: self.y.div(rhs.y),
         }
     }
 }
@@ -195,21 +198,21 @@ impl Div<f32> for Hex {
 impl DivAssign for Hex {
     #[inline]
     fn div_assign(&mut self, rhs: Self) {
-        *self = *self / rhs;
+        *self = self.div(rhs);
     }
 }
 
 impl DivAssign<i32> for Hex {
     #[inline]
     fn div_assign(&mut self, rhs: i32) {
-        *self = *self / rhs;
+        *self = self.div(rhs);
     }
 }
 
 impl DivAssign<f32> for Hex {
     #[inline]
     fn div_assign(&mut self, rhs: f32) {
-        *self = *self / rhs;
+        *self = self.div(rhs);
     }
 }
 
@@ -234,14 +237,14 @@ impl Rem<i32> for Hex {
 impl RemAssign for Hex {
     #[inline]
     fn rem_assign(&mut self, rhs: Self) {
-        *self = *self % rhs;
+        *self = self.rem(rhs);
     }
 }
 
 impl RemAssign<i32> for Hex {
     #[inline]
     fn rem_assign(&mut self, rhs: i32) {
-        *self = *self % rhs;
+        *self = self.rem(rhs);
     }
 }
 
@@ -253,3 +256,212 @@ impl Neg for Hex {
         self.const_neg()
     }
 }
+
+impl BitAnd for Hex {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs.x),
+            y: self.y.bitand(rhs.y),
+        }
+    }
+}
+
+impl BitOr for Hex {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs.x),
+            y: self.y.bitor(rhs.y),
+        }
+    }
+}
+
+impl BitXor for Hex {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs.x),
+            y: self.y.bitxor(rhs.y),
+        }
+    }
+}
+
+impl BitAnd<i32> for Hex {
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.bitand(rhs),
+            y: self.y.bitand(rhs),
+        }
+    }
+}
+
+impl BitOr<i32> for Hex {
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.bitor(rhs),
+            y: self.y.bitor(rhs),
+        }
+    }
+}
+
+impl BitXor<i32> for Hex {
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.bitxor(rhs),
+            y: self.y.bitxor(rhs),
+        }
+    }
+}
+
+impl Shl<i8> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i8> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i16> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i16> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<i32> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<i32> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: i32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u8> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u8> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u8) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u16> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u16> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u16) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl<u32> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs),
+            y: self.y.shl(rhs),
+        }
+    }
+}
+
+impl Shr<u32> for Hex {
+    type Output = Self;
+    #[inline]
+    fn shr(self, rhs: u32) -> Self::Output {
+        Self {
+            x: self.x.shr(rhs),
+            y: self.y.shr(rhs),
+        }
+    }
+}
+
+impl Shl for Hex {
+    type Output = Self;
+    #[inline]
+    fn shl(self, rhs: Self) -> Self::Output {
+        Self {
+            x: self.x.shl(rhs.x),
+            y: self.y.shl(rhs.y),
+        }
+    }
+}
diff --git a/src/hex/mod.rs b/src/hex/mod.rs
index 0920aca..d424059 100644
--- a/src/hex/mod.rs
+++ b/src/hex/mod.rs
@@ -56,12 +56,26 @@ impl Hex {
     pub const ZERO: Self = Self::new(0, 0);
     /// (1, 1)
     pub const ONE: Self = Self::new(1, 1);
+    /// (-1, -1)
+    pub const NEG_ONE: Self = Self::ONE.const_neg();
+
     /// X (Q) axis (1, 0)
     pub const X: Self = Self::new(1, 0);
+    /// -X (-Q) axis (-1, 0)
+    pub const NEG_X: Self = Self::X.const_neg();
     /// Y (R) axis (0, 1)
     pub const Y: Self = Self::new(0, 1);
-    /// Z (S) axis (0, -1)
+    /// -Y (-R) axis (0, -1)
+    pub const NEG_Y: Self = Self::new(0, -1);
+    /// Z (S) axis (0, -1, **1**)
     pub const Z: Self = Self::new(0, -1);
+    /// -Z (S) axis (0, 1, **-1**)
+    pub const NEG_Z: Self = Self::Y;
+
+    /// The unit axes.
+    pub const AXES: [Self; 2] = [Self::X, Self::Y];
+    /// The cubic unit axes.
+    pub const CUBIC_AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
 
     /// Hexagon neighbor coordinates array, following [`Direction`] order
     ///
@@ -80,11 +94,11 @@ impl Hex {
     /// ```
     pub const NEIGHBORS_COORDS: [Self; 6] = [
         Self::new(1, -1),
-        Self::new(0, -1),
-        Self::new(-1, 0),
+        Self::NEG_Y,
+        Self::NEG_X,
         Self::new(-1, 1),
-        Self::new(0, 1),
-        Self::new(1, 0),
+        Self::Y,
+        Self::X,
     ];
 
     /// ```txt
@@ -103,10 +117,10 @@ impl Hex {
     pub const DIAGONAL_COORDS: [Self; 6] = [
         Self::new(2, -1),
         Self::new(1, -2),
-        Self::new(-1, -1),
+        Self::NEG_ONE,
         Self::new(-2, 1),
         Self::new(-1, 2),
-        Self::new(1, 1),
+        Self::ONE,
     ];
 
     #[inline]
@@ -227,6 +241,28 @@ impl Hex {
         [self.x, self.y, self.z()]
     }
 
+    // Creates a [`Hex`] from the first 2 values in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 2 elements long.
+    #[inline]
+    #[must_use]
+    pub const fn from_slice(slice: &[i32]) -> Self {
+        Self::new(slice[0], slice[1])
+    }
+
+    /// Writes the elements of `self` to the first 2 elements in `slice`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `slice` is less than 2 elements long.
+    #[inline]
+    pub fn write_to_slice(self, slice: &mut [i32]) {
+        slice[0] = self.x;
+        slice[1] = self.y;
+    }
+
     #[must_use]
     #[inline]
     /// Converts `self` to an [`IVec2`].
@@ -360,6 +396,50 @@ impl Hex {
             y: self.y.abs(),
         }
     }
+    /// Returns a vector containing the minimum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.min(rhs.x), self.y.min(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn min(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+        }
+    }
+
+    /// Returns a vector containing the maximum values for each element of `self` and `rhs`.
+    ///
+    /// In other words this computes `[self.x.max(rhs.x), self.y.max(rhs.y), ..]`.
+    #[inline]
+    #[must_use]
+    pub fn max(self, rhs: Self) -> Self {
+        Self {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+        }
+    }
+
+    /// Computes the dot product of `self` and `rhs`.
+    #[inline]
+    #[must_use]
+    pub const fn dot(self, rhs: Self) -> i32 {
+        (self.x * rhs.x) + (self.y * rhs.y)
+    }
+
+    #[inline]
+    #[must_use]
+    /// Returns a [`Hex`] with elements representing the sign of `self`.
+    ///
+    ///  - `0` if the number is zero
+    ///  - `1` if the number is positive
+    ///  - `-1` if the number is negative
+    pub const fn signum(self) -> Self {
+        Self {
+            x: self.x.signum(),
+            y: self.y.signum(),
+        }
+    }
 
     #[inline]
     #[must_use]


Test patch:
diff --git a/src/hex/tests.rs b/src/hex/tests.rs
index bc9092e..365d591 100644
--- a/src/hex/tests.rs
+++ b/src/hex/tests.rs
@@ -28,6 +28,14 @@ fn hex_sum() {
     );
 }
 
+#[test]
+fn hex_product() {
+    assert_eq!(
+        Hex::X.line_to(Hex::new(5, 0)).product::<Hex>(),
+        Hex::new((1..=5).product(), 0)
+    );
+}
+
 #[test]
 fn hex_length() {
     assert_eq!(Hex::ZERO.length(), 0);