use crate::continent::{ContinentSize, Coord};
use crate::error::{Error, Result};
use derive_more::{Deref, Display, From, Into};
use nil_num::BigIntUsize;
use std::ops::{Div, Rem};
#[derive(
Clone, Copy, Debug, Deref, Display, From, Into, PartialEq, Eq, PartialOrd, Ord, Hash, BigIntUsize,
)]
pub struct ContinentIndex(usize);
impl ContinentIndex {
#[inline]
pub const fn new(index: usize) -> Self {
Self(index)
}
#[inline]
pub const fn as_usize(self) -> usize {
self.0
}
pub fn from_coord(coord: Coord, size: ContinentSize) -> Self {
let size = usize::from(size);
let x = usize::from(coord.x());
let y = usize::from(coord.y());
let index = (y * size) + x;
debug_assert!(x < size);
debug_assert!(y < size);
ContinentIndex(index)
}
pub fn to_coord(self, size: ContinentSize) -> Result<Coord> {
let x = self % size;
let y = self / size;
debug_assert!(x < size);
debug_assert!(y < size);
Ok(Coord::new(
u8::try_from(x).map_err(|_| Error::IndexOutOfBounds(self))?,
u8::try_from(y).map_err(|_| Error::IndexOutOfBounds(self))?,
))
}
}
impl Div<usize> for ContinentIndex {
type Output = usize;
fn div(self, rhs: usize) -> Self::Output {
self.0 / rhs
}
}
impl Div<ContinentSize> for ContinentIndex {
type Output = usize;
fn div(self, rhs: ContinentSize) -> Self::Output {
self.0 / usize::from(rhs)
}
}
impl Rem<usize> for ContinentIndex {
type Output = usize;
fn rem(self, rhs: usize) -> Self::Output {
self.0 % rhs
}
}
impl Rem<ContinentSize> for ContinentIndex {
type Output = usize;
fn rem(self, rhs: ContinentSize) -> Self::Output {
self.0 % usize::from(rhs)
}
}
pub trait ContinentKey {
fn into_index(self, size: ContinentSize) -> ContinentIndex;
fn into_coord(self, size: ContinentSize) -> Result<Coord>
where
Self: Sized,
{
self.into_index(size).to_coord(size)
}
}
impl ContinentKey for ContinentIndex {
fn into_index(self, _: ContinentSize) -> ContinentIndex {
self
}
}
impl ContinentKey for Coord {
fn into_index(self, size: ContinentSize) -> ContinentIndex {
ContinentIndex::from_coord(self, size)
}
fn into_coord(self, _: ContinentSize) -> Result<Coord>
where
Self: Sized,
{
Ok(self)
}
}
impl ContinentKey for usize {
fn into_index(self, _: ContinentSize) -> ContinentIndex {
ContinentIndex::new(self)
}
}