Skip to content

Commit

Permalink
Migrate Qa to u16
Browse files Browse the repository at this point in the history
  • Loading branch information
lpenz committed Aug 31, 2021
1 parent 1f6c7bf commit 13a5406
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 55 deletions.
124 changes: 87 additions & 37 deletions src/_sqrid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ use std::ops;
/// type Qa = sqrid::Qa<4, 4>;
/// ```
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Qa<const WIDTH: i16, const HEIGHT: i16> {
x: i16,
y: i16,
pub struct Qa<const WIDTH: u16, const HEIGHT: u16> {
x: u16,
y: u16,
}

impl<const W: i16, const H: i16> Qa<W, H> {
impl<const W: u16, const H: u16> Qa<W, H> {
/// Width of the grid: exclusive max of the x coordinate.
pub const WIDTH: i16 = W;
pub const WIDTH: u16 = W;

/// Height of the grid: exclusive max of the y coordinate.
pub const HEIGHT: i16 = H;
pub const HEIGHT: u16 = H;

/// Size of the grid, i.e. how many squares.
pub const SIZE: usize = W as usize * H as usize;
Expand All @@ -57,10 +57,10 @@ impl<const W: i16, const H: i16> Qa<W, H> {
/// Create a new [`Qa`] instance.
/// Can be used in const context.
/// Bounds are checked at compile-time, if possible.
pub const fn new<const X: i16, const Y: i16>() -> Self {
pub const fn new<const X: u16, const Y: u16>() -> Self {
// Trick for compile-time check of X and Y:
const ASSERT_FALSE: [(); 1] = [(); 1];
let _ = ASSERT_FALSE[(X < 0 || X >= W || Y < 0 || Y >= H) as usize];
let _ = ASSERT_FALSE[(X >= W || Y >= H) as usize];
Self { x: X, y: Y }
}

Expand All @@ -76,60 +76,93 @@ impl<const W: i16, const H: i16> Qa<W, H> {
}
}

impl<const W: i16, const H: i16> fmt::Display for Qa<W, H> {
impl<const W: u16, const H: u16> fmt::Display for Qa<W, H> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({},{})", self.x, self.y)
}
}

// TryFrom / Into tuple

impl<const W: i16, const H: i16> convert::TryFrom<&(i16, i16)> for Qa<W, H> {
impl<const W: u16, const H: u16> convert::TryFrom<&(u16, u16)> for Qa<W, H> {
type Error = Error;
fn try_from(xy: &(i16, i16)) -> Result<Self, Self::Error> {
if xy.0 < 0 || xy.1 < 0 || xy.0 >= W || xy.1 >= H {
fn try_from(xy: &(u16, u16)) -> Result<Self, Self::Error> {
if xy.0 >= W || xy.1 >= H {
Err(Error::OutOfBounds)
} else {
Ok(Qa { x: xy.0, y: xy.1 })
}
}
}

impl<const W: i16, const H: i16> convert::TryFrom<(i16, i16)> for Qa<W, H> {
impl<const W: u16, const H: u16> convert::TryFrom<(u16, u16)> for Qa<W, H> {
type Error = Error;
fn try_from(xy: (i16, i16)) -> Result<Self, Self::Error> {
fn try_from(xy: (u16, u16)) -> Result<Self, Self::Error> {
Self::try_from(&xy)
}
}

impl<const W: i16, const H: i16> From<&Qa<W, H>> for (i16, i16) {
impl<const W: u16, const H: u16> convert::TryFrom<&(i32, i32)> for Qa<W, H> {
type Error = Error;
fn try_from(xy: &(i32, i32)) -> Result<Self, Self::Error> {
if xy.0 < 0 || xy.1 < 0 || xy.0 >= W as i32 || xy.1 >= H as i32 {
Err(Error::OutOfBounds)
} else {
Ok(Qa {
x: xy.0 as u16,
y: xy.1 as u16,
})
}
}
}

impl<const W: u16, const H: u16> convert::TryFrom<(i32, i32)> for Qa<W, H> {
type Error = Error;
fn try_from(xy: (i32, i32)) -> Result<Self, Self::Error> {
Self::try_from(&xy)
}
}

impl<const W: u16, const H: u16> From<&Qa<W, H>> for (u16, u16) {
fn from(qa: &Qa<W, H>) -> Self {
(qa.x, qa.y)
}
}

impl<const W: i16, const H: i16> From<Qa<W, H>> for (i16, i16) {
impl<const W: u16, const H: u16> From<Qa<W, H>> for (u16, u16) {
fn from(qa: Qa<W, H>) -> Self {
<(i16, i16)>::from(&qa)
<(u16, u16)>::from(&qa)
}
}

impl<const W: u16, const H: u16> From<&Qa<W, H>> for (i32, i32) {
fn from(qa: &Qa<W, H>) -> Self {
(qa.x as i32, qa.y as i32)
}
}

impl<const W: u16, const H: u16> From<Qa<W, H>> for (i32, i32) {
fn from(qa: Qa<W, H>) -> Self {
<(i32, i32)>::from(&qa)
}
}

// TryFrom / Into usize index

impl<const W: i16, const H: i16> convert::TryFrom<usize> for Qa<W, H> {
impl<const W: u16, const H: u16> convert::TryFrom<usize> for Qa<W, H> {
type Error = Error;
fn try_from(i: usize) -> Result<Self, Self::Error> {
if i >= Qa::<W, H>::SIZE {
Err(Error::OutOfBounds)
} else {
let x = (i % W as usize) as i16;
let y = (i / W as usize) as i16;
let x = (i % W as usize) as u16;
let y = (i / W as usize) as u16;
Ok(Qa { x, y })
}
}
}

impl<const W: i16, const H: i16> From<Qa<W, H>> for usize {
impl<const W: u16, const H: u16> From<Qa<W, H>> for usize {
fn from(qa: Qa<W, H>) -> Self {
qa.y as usize * W as usize + qa.x as usize
}
Expand All @@ -149,15 +182,15 @@ impl<const W: i16, const H: i16> From<Qa<W, H>> for usize {
/// }
/// ```
#[derive(Debug, Clone, Copy)]
pub struct QaIterator<const W: i16, const H: i16>(Option<Qa<W, H>>);
pub struct QaIterator<const W: u16, const H: u16>(Option<Qa<W, H>>);

impl<const W: i16, const H: i16> Default for QaIterator<W, H> {
impl<const W: u16, const H: u16> Default for QaIterator<W, H> {
fn default() -> Self {
QaIterator(Some(Default::default()))
}
}

impl<const W: i16, const H: i16> Iterator for QaIterator<W, H> {
impl<const W: u16, const H: u16> Iterator for QaIterator<W, H> {
type Item = Qa<W, H>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(i) = self.0.take() {
Expand Down Expand Up @@ -230,7 +263,7 @@ impl Qr {
/// All corresponding tuples
///
/// Used to convert a [`Qr`] value into a (i16, i16) tuple via indexing.
pub const TUPLES: [(i16, i16); 8] = [
pub const TUPLES: [(i8, i8); 8] = [
(0, -1),
(1, -1),
(1, 0),
Expand Down Expand Up @@ -295,9 +328,9 @@ impl Qr {

// TryFrom / Into tuple

impl convert::TryFrom<&(i16, i16)> for Qr {
impl convert::TryFrom<&(i8, i8)> for Qr {
type Error = Error;
fn try_from(xy: &(i16, i16)) -> Result<Self, Self::Error> {
fn try_from(xy: &(i8, i8)) -> Result<Self, Self::Error> {
if xy.0 < -1 || xy.0 > 1 || xy.1 < -1 || xy.1 > 1 || (xy.0 == 0 && xy.1 == 0) {
Err(Error::InvalidDirection)
} else {
Expand All @@ -306,22 +339,35 @@ impl convert::TryFrom<&(i16, i16)> for Qr {
}
}

impl convert::TryFrom<(i16, i16)> for Qr {
impl convert::TryFrom<(i8, i8)> for Qr {
type Error = Error;
fn try_from(xy: (i16, i16)) -> Result<Self, Self::Error> {
fn try_from(xy: (i8, i8)) -> Result<Self, Self::Error> {
Self::try_from(&xy)
}
}

impl From<&Qr> for (i16, i16) {
impl From<&Qr> for (i8, i8) {
fn from(qr: &Qr) -> Self {
Qr::TUPLES[*qr as usize]
}
}

impl From<Qr> for (i16, i16) {
impl From<Qr> for (i8, i8) {
fn from(qr: Qr) -> Self {
<(i16, i16)>::from(&qr)
<(i8, i8)>::from(&qr)
}
}

impl From<&Qr> for (i32, i32) {
fn from(qr: &Qr) -> Self {
let tuple = Qr::TUPLES[*qr as usize];
(tuple.0 as i32, tuple.1 as i32)
}
}

impl From<Qr> for (i32, i32) {
fn from(qr: Qr) -> Self {
<(i32, i32)>::from(&qr)
}
}

Expand All @@ -333,7 +379,7 @@ impl From<&Qr> for usize {

impl From<Qr> for usize {
fn from(qr: Qr) -> usize {
qr as usize
usize::from(&qr)
}
}

Expand Down Expand Up @@ -394,12 +440,16 @@ impl<const D: bool> Iterator for QrIterator<D> {

/* Interaction between Qa and Qr: ***********************************/

impl<const W: i16, const H: i16> ops::Add<Qr> for Qa<W, H> {
impl<const W: u16, const H: u16> ops::Add<Qr> for Qa<W, H> {
type Output = Option<Self>;
fn add(self, rhs: Qr) -> Self::Output {
let qat = <(i16, i16)>::from(self);
let qrt = <(i16, i16)>::from(rhs);
Qa::<W, H>::try_from((qat.0 + qrt.0, qat.1 + qrt.1)).ok()
let qat = <(i32, i32)>::from(self);
let qrt = <(i32, i32)>::from(rhs);
if qat.0 == 0 && qrt.0 < 0 || qat.1 == 0 && qrt.1 < 0 {
None
} else {
Qa::<W, H>::try_from((qat.0 + qrt.0, qat.1 + qrt.1)).ok()
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
//! type Qa = sqrid::Qa<6, 7>;
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//! let qa1 = Qa::try_from((2_i16, 3_i16))?;
//! let qa1 = Qa::try_from((2_u16, 3_u16))?;
//!
//! println!("qa1: {}", qa1);
//! Ok(())
Expand Down Expand Up @@ -88,9 +88,9 @@
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//! // Re-create West:
//! let qr1 = Qr::try_from((0_i16, -1_i16))?;
//! let qr1 = Qr::try_from((0_i8, -1_i8))?;
//! // Re-create Northeast:
//! let qr2 = Qr::try_from((-1_i16, 1_i16))?;
//! let qr2 = Qr::try_from((-1_i8, 1_i8))?;
//! Ok(())
//! }
//! ```
Expand Down
22 changes: 10 additions & 12 deletions tests/qa_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ type Qa = sqrid::Qa<6, 7>;

#[test]
fn test_basic() -> Result<()> {
let q1 = Qa::try_from((2_i16, 3_i16))?;
let q1 = Qa::try_from((2_u16, 3_u16))?;
println!("{:?} {}", q1, q1);
assert_eq!((2_i16, 3_i16), q1.into());
let q2 = Qa::try_from(&(3_i16, 4_i16))?;
assert_eq!((3_i16, 4_i16), q2.into());
let q3 = Qa::try_from(&(5_i16, 6_i16));
assert_eq!((5_i16, 6_i16), q3.unwrap().into());
assert_eq!((2_u16, 3_u16), q1.into());
let q2 = Qa::try_from(&(3_u16, 4_u16))?;
assert_eq!((3_u16, 4_u16), q2.into());
let q3 = Qa::try_from(&(5_u16, 6_u16));
assert_eq!((5_u16, 6_u16), q3.unwrap().into());
const Q4: Qa = Qa::new::<5, 4>();
assert_eq!((5_i16, 4_i16), Q4.into());
assert_eq!((5_u16, 4_u16), Q4.into());
let q5 = Qa::new::<4, 3>();
assert_eq!((4_i16, 3_i16), q5.into());
assert_eq!((4_u16, 3_u16), q5.into());
Ok(())
}

Expand All @@ -34,17 +34,15 @@ fn test_usize() -> Result<()> {

#[test]
fn test_out_of_bounds() -> Result<()> {
let q1result = Qa::try_from((6_i16, 3_i16));
let q1result = Qa::try_from((6_u16, 3_u16));
assert!(q1result.is_err());
println!("{:?}", q1result);
println!("{}", q1result.unwrap_err());
let q2result = Qa::try_from((0_i16, 7_i16));
let q2result = Qa::try_from((0_u16, 7_u16));
assert!(q2result.is_err());
assert_eq!(q2result.unwrap_err(), sqrid::Error::OutOfBounds);
let q3result = Qa::try_from(Qa::SIZE);
assert_eq!(q3result.unwrap_err(), sqrid::Error::OutOfBounds);
let q4result = Qa::try_from((-1_i16, 0_i16));
assert_eq!(q4result.unwrap_err(), sqrid::Error::OutOfBounds);
Ok(())
}

Expand Down
6 changes: 3 additions & 3 deletions tests/qr_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ fn test_basic() -> Result<()> {
let qr0 = Qr::default();
let qr1 = Qr::N;
assert_eq!(qr0, qr1);
assert_eq!(<(i16, i16)>::from(qr1), (0, -1));
let qr2 = Qr::try_from((-1_i16, 0_i16));
assert_eq!(<(i8, i8)>::from(qr1), (0, -1));
let qr2 = Qr::try_from((-1_i8, 0_i8));
assert_eq!(qr2, Ok(Qr::W));
Ok(())
}

#[test]
fn test_errors() -> Result<()> {
let qr1result = Qr::try_from((2_i16, 0_i16));
let qr1result = Qr::try_from((2_i8, 0_i8));
println!("{}", qr1result.clone().unwrap_err());
assert_eq!(qr1result.unwrap_err(), sqrid::Error::InvalidDirection);
Ok(())
Expand Down

0 comments on commit 13a5406

Please sign in to comment.