Skip to main content

nil_core/resources/
gold.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::market::fee::MarketFee;
5use crate::resources::Resources;
6use derive_more::Display;
7use nil_num::impl_mul_ceil;
8use nil_num::mul_ceil::MulCeil;
9use nil_util::{ConstDeref, F64Math};
10use serde::{Deserialize, Serialize};
11use std::iter::Sum;
12use std::ops::{Add, AddAssign, Mul, Sub, SubAssign};
13
14/// Gold is a special resource used to trade in the market.
15#[derive(Copy, Debug, Display, Deserialize, Serialize, ConstDeref, F64Math)]
16#[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
17#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
18pub struct Gold(u32);
19
20impl Gold {
21  pub const MIN: Self = Self::new(0);
22  pub const MAX: Self = Self::new(u32::MAX);
23
24  #[inline]
25  pub const fn new(value: u32) -> Self {
26    Self(value)
27  }
28
29  #[inline]
30  pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
31    self.0.checked_sub(rhs.0).map(Self::new)
32  }
33}
34
35impl_mul_ceil!(Gold);
36
37const impl From<u32> for Gold {
38  fn from(value: u32) -> Self {
39    Self::new(value)
40  }
41}
42
43const impl From<Gold> for u32 {
44  fn from(value: Gold) -> Self {
45    value.0
46  }
47}
48
49const impl From<f64> for Gold {
50  fn from(value: f64) -> Self {
51    debug_assert!(value.is_finite());
52    debug_assert!(value >= 0.0);
53    Self(value.trunc() as u32)
54  }
55}
56
57const impl From<Gold> for f64 {
58  fn from(value: Gold) -> Self {
59    f64::from(value.0)
60  }
61}
62
63const impl From<Resources> for Gold {
64  fn from(value: Resources) -> Self {
65    // It's better to destructure here so the compiler will warn us
66    // if we add new resources in the future and forget to update this.
67    let Resources { food, iron, stone, wood } = value;
68
69    Gold(0)
70      .add(Gold::from(food))
71      .add(Gold::from(iron))
72      .add(Gold::from(stone))
73      .add(Gold::from(wood))
74  }
75}
76
77const impl Add for Gold {
78  type Output = Gold;
79
80  fn add(self, rhs: Gold) -> Self::Output {
81    Self::new(self.0.saturating_add(rhs.0))
82  }
83}
84
85const impl Add<Resources> for Gold {
86  type Output = Gold;
87
88  fn add(self, rhs: Resources) -> Self::Output {
89    self + Gold::from(rhs)
90  }
91}
92
93const impl AddAssign for Gold {
94  fn add_assign(&mut self, rhs: Gold) {
95    *self = *self + rhs;
96  }
97}
98
99const impl AddAssign<Resources> for Gold {
100  fn add_assign(&mut self, rhs: Resources) {
101    *self = *self + rhs;
102  }
103}
104
105const impl Sub for Gold {
106  type Output = Gold;
107
108  fn sub(self, rhs: Gold) -> Self::Output {
109    Self::new(self.0.saturating_sub(rhs.0))
110  }
111}
112
113const impl SubAssign for Gold {
114  fn sub_assign(&mut self, rhs: Gold) {
115    *self = *self - rhs;
116  }
117}
118
119const impl Mul<u32> for Gold {
120  type Output = Gold;
121
122  fn mul(self, rhs: u32) -> Self::Output {
123    Self::new(self.0.saturating_mul(rhs))
124  }
125}
126
127const impl Mul<MarketFee> for Gold {
128  type Output = Gold;
129
130  fn mul(self, rhs: MarketFee) -> Self::Output {
131    Self::from(self.mul_ceil(*rhs))
132  }
133}
134
135impl Sum<Gold> for Gold {
136  fn sum<I>(iter: I) -> Self
137  where
138    I: Iterator<Item = Gold>,
139  {
140    iter.fold(Gold::default(), |acc, gold| acc + gold)
141  }
142}
143
144impl Sum<Resources> for Gold {
145  fn sum<I>(iter: I) -> Self
146  where
147    I: Iterator<Item = Resources>,
148  {
149    iter.fold(Gold::default(), |acc, resources| acc + resources)
150  }
151}