1use borsh::{BorshDeserialize as Deserialize, BorshSerialize as Serialize};
7use bytemuck::{Pod, Zeroable};
8use std::fmt::Display;
9use std::iter::Sum;
10use std::ops::{Add, AddAssign, Div, Mul, Rem, Sub, SubAssign};
11
12pub trait WrapperU64 {
13 fn new(value: u64) -> Self;
14 fn as_u64(&self) -> u64;
15}
16
17macro_rules! basic_u64_struct {
18 ($type_name:ident) => {
19 #[derive(Debug, Clone, Copy, PartialOrd, Ord, Zeroable, Pod)]
20 #[repr(transparent)]
21 pub struct $type_name {
22 inner: u64,
23 }
24
25 basic_u64!($type_name);
26 };
27}
28
29macro_rules! basic_u64 {
30 ($type_name:ident) => {
31 impl WrapperU64 for $type_name {
32 fn new(value: u64) -> Self {
33 $type_name { inner: value }
34 }
35
36 fn as_u64(&self) -> u64 {
37 self.inner
38 }
39 }
40
41 impl $type_name {
42 pub const ZERO: Self = $type_name { inner: 0 };
43 pub const ONE: Self = $type_name { inner: 1 };
44 pub const MAX: Self = $type_name { inner: u64::MAX };
45 pub const MIN: Self = $type_name { inner: u64::MIN };
46 pub fn as_u128(&self) -> u128 {
47 self.inner as u128
48 }
49
50 pub fn saturating_sub(self, other: Self) -> Self {
51 $type_name::new(self.inner.saturating_sub(other.inner))
52 }
53
54 pub fn unchecked_div<Divisor: WrapperU64, Quotient: WrapperU64>(
55 self,
56 other: Divisor,
57 ) -> Quotient {
58 Quotient::new(self.inner / other.as_u64())
59 }
60 }
61
62 impl Display for $type_name {
63 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
64 self.inner.fmt(f)
65 }
66 }
67
68 impl Mul for $type_name {
69 type Output = Self;
70 fn mul(self, other: Self) -> Self {
71 $type_name::new(self.inner * other.inner)
72 }
73 }
74
75 impl Sum<$type_name> for $type_name {
76 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
77 iter.fold($type_name::ZERO, |acc, x| acc + x)
78 }
79 }
80
81 impl Add for $type_name {
82 type Output = Self;
83 fn add(self, other: Self) -> Self {
84 $type_name::new(self.inner + other.inner)
85 }
86 }
87
88 impl AddAssign for $type_name {
89 fn add_assign(&mut self, other: Self) {
90 *self = *self + other;
91 }
92 }
93
94 impl Sub for $type_name {
95 type Output = Self;
96
97 fn sub(self, other: Self) -> Self {
98 $type_name::new(self.inner - other.inner)
99 }
100 }
101
102 impl SubAssign for $type_name {
103 fn sub_assign(&mut self, other: Self) {
104 *self = *self - other;
105 }
106 }
107
108 impl Default for $type_name {
109 fn default() -> Self {
110 Self::ZERO
111 }
112 }
113
114 impl PartialEq for $type_name {
115 fn eq(&self, other: &Self) -> bool {
116 self.inner == other.inner
117 }
118 }
119
120 impl From<$type_name> for u64 {
121 fn from(x: $type_name) -> u64 {
122 x.inner
123 }
124 }
125
126 impl From<$type_name> for f64 {
127 fn from(x: $type_name) -> f64 {
128 x.inner as f64
129 }
130 }
131
132 impl Eq for $type_name {}
133
134 impl PartialEq<u64> for $type_name {
136 fn eq(&self, other: &u64) -> bool {
137 self.inner == *other
138 }
139 }
140
141 impl PartialEq<$type_name> for u64 {
142 fn eq(&self, other: &$type_name) -> bool {
143 *self == other.inner
144 }
145 }
146 };
147}
148
149macro_rules! allow_multiply {
150 ($type_1:ident, $type_2:ident, $type_result:ident) => {
151 impl Mul<$type_2> for $type_1 {
152 type Output = $type_result;
153 fn mul(self, other: $type_2) -> $type_result {
154 $type_result::new(self.inner * other.inner)
155 }
156 }
157
158 impl Mul<$type_1> for $type_2 {
159 type Output = $type_result;
160 fn mul(self, other: $type_1) -> $type_result {
161 $type_result::new(self.inner * other.inner)
162 }
163 }
164
165 impl Div<$type_1> for $type_result {
166 type Output = $type_2;
167 #[track_caller]
168 fn div(self, other: $type_1) -> $type_2 {
169 if self.inner % other.inner != 0 {
170 let caller = std::panic::Location::caller();
171
172 phoenix_log!(
173 "WARNING: Expected clean division, but received {:?} / {:?}. Caller: {:?}",
174 self,
175 other,
176 caller
177 );
178 }
179 $type_2::new(self.inner / other.inner)
180 }
181 }
182
183 impl Div<$type_2> for $type_result {
184 type Output = $type_1;
185 #[track_caller]
186 fn div(self, other: $type_2) -> $type_1 {
187 if self.inner % other.inner != 0 {
188 let caller = std::panic::Location::caller();
189
190 phoenix_log!(
191 "WARNING: Expected clean division, but received {:?} / {:?}. Caller: {:?}",
192 self,
193 other,
194 caller
195 );
196 }
197 $type_1::new(self.inner / other.inner)
198 }
199 }
200 };
201}
202
203macro_rules! allow_mod {
204 ($type_1:ident, $type_2:ident) => {
205 impl Rem<$type_2> for $type_1 {
206 type Output = u64;
207 fn rem(self, other: $type_2) -> u64 {
208 self.inner % other.inner
209 }
210 }
211 };
212}
213
214#[derive(Debug, Clone, Copy, PartialOrd, Ord, Zeroable, Pod, Deserialize, Serialize)]
217#[repr(transparent)]
218pub struct QuoteLots {
219 inner: u64,
220}
221#[derive(Debug, Clone, Copy, PartialOrd, Ord, Zeroable, Pod, Deserialize, Serialize)]
222#[repr(transparent)]
223pub struct BaseLots {
224 inner: u64,
225}
226
227#[derive(Debug, Clone, Copy, PartialOrd, Ord, Zeroable, Pod, Deserialize, Serialize)]
228#[repr(transparent)]
229pub struct Ticks {
230 inner: u64,
231}
232
233basic_u64!(QuoteLots);
234basic_u64!(BaseLots);
235
236basic_u64!(Ticks);
238
239basic_u64_struct!(QuoteAtoms);
241basic_u64_struct!(BaseAtoms);
242basic_u64_struct!(QuoteUnits);
243basic_u64_struct!(BaseUnits);
244
245basic_u64_struct!(QuoteAtomsPerQuoteLot);
247basic_u64_struct!(BaseAtomsPerBaseLot);
248basic_u64_struct!(BaseLotsPerBaseUnit);
249basic_u64_struct!(QuoteLotsPerQuoteUnit);
250basic_u64_struct!(QuoteAtomsPerQuoteUnit);
251basic_u64_struct!(BaseAtomsPerBaseUnit);
252
253basic_u64_struct!(QuoteAtomsPerBaseUnitPerTick);
255basic_u64_struct!(QuoteLotsPerBaseUnitPerTick);
256
257basic_u64_struct!(AdjustedQuoteLots);
258basic_u64_struct!(QuoteLotsPerBaseUnit);
259
260allow_multiply!(BaseUnits, BaseLotsPerBaseUnit, BaseLots);
262allow_multiply!(QuoteUnits, QuoteLotsPerQuoteUnit, QuoteLots);
263allow_multiply!(QuoteLots, QuoteAtomsPerQuoteLot, QuoteAtoms);
265allow_multiply!(BaseLots, BaseAtomsPerBaseLot, BaseAtoms);
266
267allow_multiply!(
269 BaseAtomsPerBaseLot,
270 BaseLotsPerBaseUnit,
271 BaseAtomsPerBaseUnit
272);
273allow_multiply!(
274 QuoteAtomsPerQuoteLot,
275 QuoteLotsPerQuoteUnit,
276 QuoteAtomsPerQuoteUnit
277);
278
279allow_multiply!(
281 QuoteLotsPerBaseUnitPerTick,
282 QuoteAtomsPerQuoteLot,
283 QuoteAtomsPerBaseUnitPerTick
284);
285
286allow_multiply!(QuoteLotsPerBaseUnitPerTick, Ticks, QuoteLotsPerBaseUnit);
288
289allow_multiply!(QuoteLots, BaseLotsPerBaseUnit, AdjustedQuoteLots);
291
292allow_multiply!(QuoteLotsPerBaseUnit, BaseLots, AdjustedQuoteLots);
294
295allow_mod!(AdjustedQuoteLots, BaseLotsPerBaseUnit);
296allow_mod!(BaseAtomsPerBaseUnit, BaseLotsPerBaseUnit);
297allow_mod!(QuoteAtomsPerQuoteUnit, QuoteLotsPerQuoteUnit);
298allow_mod!(QuoteLotsPerBaseUnitPerTick, BaseLotsPerBaseUnit);
299
300#[test]
301fn test_new_constructor_macro() {
302 let base_lots_1 = BaseLots::new(5);
303 let base_lots_2 = BaseLots::new(10);
304
305 assert_eq!(base_lots_1 + base_lots_2, BaseLots::new(15));
306
307 }
311
312#[test]
313fn test_multiply_macro() {
314 let base_units = BaseUnits::new(5);
315 let base_lots_per_base_unit = BaseLotsPerBaseUnit::new(100);
316 assert_eq!(base_units * base_lots_per_base_unit, BaseLots::new(500));
317
318 }