Skip to main content

nil_core/continent/
index.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::continent::{ContinentSize, Coord};
5use crate::error::{Error, Result};
6use derive_more::{Deref, Display, From, Into};
7use nil_num::BigIntUsize;
8use std::ops::{Div, Rem};
9
10#[derive(
11  Clone, Copy, Debug, Deref, Display, From, Into, PartialEq, Eq, PartialOrd, Ord, Hash, BigIntUsize,
12)]
13pub struct ContinentIndex(usize);
14
15impl ContinentIndex {
16  #[inline]
17  pub const fn new(index: usize) -> Self {
18    Self(index)
19  }
20
21  #[inline]
22  pub const fn as_usize(self) -> usize {
23    self.0
24  }
25
26  pub fn from_coord(coord: Coord, size: ContinentSize) -> Self {
27    let size = usize::from(size);
28    let x = usize::from(coord.x());
29    let y = usize::from(coord.y());
30    let index = (y * size) + x;
31
32    debug_assert!(x < size);
33    debug_assert!(y < size);
34
35    ContinentIndex(index)
36  }
37
38  pub fn to_coord(self, size: ContinentSize) -> Result<Coord> {
39    let x = self % size;
40    let y = self / size;
41
42    debug_assert!(x < size);
43    debug_assert!(y < size);
44
45    Ok(Coord::new(
46      u8::try_from(x).map_err(|_| Error::IndexOutOfBounds(self))?,
47      u8::try_from(y).map_err(|_| Error::IndexOutOfBounds(self))?,
48    ))
49  }
50}
51
52impl Div<usize> for ContinentIndex {
53  type Output = usize;
54
55  fn div(self, rhs: usize) -> Self::Output {
56    self.0 / rhs
57  }
58}
59
60impl Div<ContinentSize> for ContinentIndex {
61  type Output = usize;
62
63  fn div(self, rhs: ContinentSize) -> Self::Output {
64    self.0 / usize::from(rhs)
65  }
66}
67
68impl Rem<usize> for ContinentIndex {
69  type Output = usize;
70
71  fn rem(self, rhs: usize) -> Self::Output {
72    self.0 % rhs
73  }
74}
75
76impl Rem<ContinentSize> for ContinentIndex {
77  type Output = usize;
78
79  fn rem(self, rhs: ContinentSize) -> Self::Output {
80    self.0 % usize::from(rhs)
81  }
82}
83
84pub trait ContinentKey {
85  fn into_index(self, size: ContinentSize) -> ContinentIndex;
86
87  fn into_coord(self, size: ContinentSize) -> Result<Coord>
88  where
89    Self: Sized,
90  {
91    self.into_index(size).to_coord(size)
92  }
93}
94
95impl ContinentKey for ContinentIndex {
96  fn into_index(self, _: ContinentSize) -> ContinentIndex {
97    self
98  }
99}
100
101impl ContinentKey for Coord {
102  fn into_index(self, size: ContinentSize) -> ContinentIndex {
103    ContinentIndex::from_coord(self, size)
104  }
105
106  fn into_coord(self, _: ContinentSize) -> Result<Coord>
107  where
108    Self: Sized,
109  {
110    Ok(self)
111  }
112}
113
114impl ContinentKey for usize {
115  fn into_index(self, _: ContinentSize) -> ContinentIndex {
116    ContinentIndex::new(self)
117  }
118}