1use std::{
2 cmp::Ordering,
3 fmt::Display,
4 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
5};
6
7use candid::{CandidType, Nat};
8use ic_stable_structures::{storable::Bound, Storable};
9use num_bigint::BigUint;
10use serde::Deserialize;
11
12use crate::{c::ECs, ES_BASES};
13
14#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub struct EDs {
17 pub val: BigUint,
18 pub decimals: u8,
19}
20
21impl Default for EDs {
22 fn default() -> Self {
23 Self {
24 val: BigUint::default(),
25 decimals: 8,
26 }
27 }
28}
29
30impl EDs {
31 pub fn new(val: BigUint, decimals: u8) -> Self {
32 if decimals > 31 {
33 unreachable!("Decimal points after 31 are not supported");
34 }
35
36 Self { val, decimals }
37 }
38
39 pub fn base(decimals: u8) -> &'static BigUint {
40 if decimals > 31 {
41 unreachable!("Decimal points after 31 are not supported");
42 }
43
44 unsafe { ES_BASES.get(decimals as usize).unwrap_unchecked() }
46 }
47
48 pub fn zero(decimals: u8) -> Self {
49 Self::new(BigUint::ZERO, decimals)
50 }
51
52 pub fn one(decimals: u8) -> Self {
53 Self {
54 val: Self::base(decimals).clone(),
55 decimals,
56 }
57 }
58
59 pub fn f0_1(decimals: u8) -> Self {
60 Self::new(Self::base(decimals) / BigUint::from(10u64), decimals)
61 }
62
63 pub fn f0_2(decimals: u8) -> Self {
64 Self::new(Self::base(decimals) / BigUint::from(5u64), decimals)
65 }
66
67 pub fn f0_25(decimals: u8) -> Self {
68 Self::new(Self::base(decimals) / BigUint::from(4u64), decimals)
69 }
70
71 pub fn f0_3(decimals: u8) -> Self {
72 Self::new(
73 Self::base(decimals) * BigUint::from(3u64) / BigUint::from(10u64),
74 decimals,
75 )
76 }
77
78 pub fn f0_33(decimals: u8) -> Self {
79 Self::new(Self::base(decimals) / BigUint::from(3u64), decimals)
80 }
81
82 pub fn f0_4(decimals: u8) -> Self {
83 Self::new(
84 Self::base(decimals) * BigUint::from(2u64) / BigUint::from(5u64),
85 decimals,
86 )
87 }
88
89 pub fn f0_5(decimals: u8) -> Self {
90 Self::new(Self::base(decimals) / BigUint::from(2u64), decimals)
91 }
92
93 pub fn f0_6(decimals: u8) -> Self {
94 Self::new(
95 Self::base(decimals) * BigUint::from(3u64) / BigUint::from(5u64),
96 decimals,
97 )
98 }
99
100 pub fn f0_67(decimals: u8) -> Self {
101 Self::new(
102 Self::base(decimals) * BigUint::from(2u64) / BigUint::from(3u64),
103 decimals,
104 )
105 }
106
107 pub fn f0_7(decimals: u8) -> Self {
108 Self::new(
109 Self::base(decimals) * BigUint::from(7u64) / BigUint::from(10u64),
110 decimals,
111 )
112 }
113
114 pub fn f0_75(decimals: u8) -> Self {
115 Self::new(
116 Self::base(decimals) * BigUint::from(3u64) / BigUint::from(4u64),
117 decimals,
118 )
119 }
120
121 pub fn f0_8(decimals: u8) -> Self {
122 Self::new(
123 Self::base(decimals) * BigUint::from(4u64) / BigUint::from(5u64),
124 decimals,
125 )
126 }
127
128 pub fn f0_9(decimals: u8) -> Self {
129 Self::new(
130 Self::base(decimals) * BigUint::from(9u64) / BigUint::from(10u64),
131 decimals,
132 )
133 }
134
135 pub fn two(decimals: u8) -> Self {
136 Self::new(Self::base(decimals) * BigUint::from(2u64), decimals)
137 }
138
139 pub fn to_const<const D: usize>(self) -> ECs<D> {
140 if self.decimals != D as u8 {
141 unreachable!(
142 "{} decimals EDs can't be transformed into E{}s!",
143 self.decimals, D
144 );
145 }
146
147 ECs::new(self.val)
148 }
149
150 pub fn to_decimals(mut self, new_decimals: u8) -> EDs {
151 if new_decimals == self.decimals {
152 return self;
153 }
154
155 let (dif, mul) = if self.decimals > new_decimals {
156 (self.decimals - new_decimals, false)
157 } else {
158 (new_decimals - self.decimals, true)
159 };
160
161 let base = Self::base(dif);
162 self.val = if mul {
163 self.val * base
164 } else {
165 self.val / base
166 };
167
168 self.decimals = new_decimals;
169
170 self
171 }
172
173 pub fn sqrt(&self) -> Self {
174 let a = Self::one(self.decimals);
175 if self == &a {
176 return a;
177 }
178
179 let mut low = Self::zero(self.decimals);
180 let mut high = self.clone();
181 let one = BigUint::from(1u64);
182
183 while (&high - &low).val > one {
184 let mid = (&low + &high) / Self::two(self.decimals);
185 let mid_squared = &mid * ∣
186
187 match mid_squared.cmp(self) {
188 Ordering::Equal => return mid,
189 Ordering::Greater => {
190 high = mid;
191 }
192 Ordering::Less => {
193 low = mid;
194 }
195 }
196 }
197
198 low
199 }
200}
201
202impl Display for EDs {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 let base = Self::base(self.decimals);
205
206 f.write_str(&format!("{}.{}", &self.val / base, &self.val % base))
207 }
208}
209
210impl Add for &EDs {
211 type Output = EDs;
212
213 fn add(self, rhs: Self) -> Self::Output {
214 if self.decimals != rhs.decimals {
215 unreachable!("Incompatible decimal points");
216 }
217
218 EDs::new(&self.val + &rhs.val, self.decimals)
219 }
220}
221
222impl Add for EDs {
223 type Output = EDs;
224
225 fn add(self, rhs: Self) -> Self::Output {
226 (&self).add(&rhs)
227 }
228}
229
230impl Add<&EDs> for EDs {
231 type Output = EDs;
232
233 fn add(self, rhs: &EDs) -> Self::Output {
234 (&self).add(rhs)
235 }
236}
237
238impl Add<EDs> for &EDs {
239 type Output = EDs;
240
241 fn add(self, rhs: EDs) -> Self::Output {
242 self.add(&rhs)
243 }
244}
245
246impl AddAssign<&EDs> for EDs {
247 fn add_assign(&mut self, rhs: &EDs) {
248 if self.decimals != rhs.decimals {
249 unreachable!("Incompatible decimal points");
250 }
251
252 self.val.add_assign(&rhs.val)
253 }
254}
255
256impl AddAssign for EDs {
257 fn add_assign(&mut self, rhs: Self) {
258 self.add_assign(&rhs)
259 }
260}
261
262impl Sub for &EDs {
263 type Output = EDs;
264
265 fn sub(self, rhs: Self) -> Self::Output {
266 if self.decimals != rhs.decimals {
267 unreachable!("Incompatible decimal points");
268 }
269
270 EDs::new(&self.val - &rhs.val, self.decimals)
271 }
272}
273
274impl Sub for EDs {
275 type Output = EDs;
276
277 fn sub(self, rhs: Self) -> Self::Output {
278 (&self).sub(&rhs)
279 }
280}
281
282impl Sub<&EDs> for EDs {
283 type Output = EDs;
284
285 fn sub(self, rhs: &EDs) -> Self::Output {
286 (&self).sub(rhs)
287 }
288}
289
290impl Sub<EDs> for &EDs {
291 type Output = EDs;
292
293 fn sub(self, rhs: EDs) -> Self::Output {
294 self.sub(&rhs)
295 }
296}
297
298impl SubAssign<&EDs> for EDs {
299 fn sub_assign(&mut self, rhs: &EDs) {
300 if self.decimals != rhs.decimals {
301 unreachable!("Incompatible decimal points");
302 }
303
304 self.val.sub_assign(&rhs.val)
305 }
306}
307
308impl SubAssign for EDs {
309 fn sub_assign(&mut self, rhs: Self) {
310 self.sub_assign(&rhs)
311 }
312}
313
314impl Mul for &EDs {
315 type Output = EDs;
316
317 fn mul(self, rhs: Self) -> Self::Output {
318 if self.decimals != rhs.decimals {
319 unreachable!("Incompatible decimal points");
320 }
321
322 EDs::new(
323 &self.val * &rhs.val / EDs::base(self.decimals),
324 self.decimals,
325 )
326 }
327}
328
329impl Mul for EDs {
330 type Output = EDs;
331
332 fn mul(self, rhs: Self) -> Self::Output {
333 (&self).mul(&rhs)
334 }
335}
336
337impl Mul<&EDs> for EDs {
338 type Output = EDs;
339
340 fn mul(self, rhs: &EDs) -> Self::Output {
341 (&self).mul(rhs)
342 }
343}
344
345impl Mul<EDs> for &EDs {
346 type Output = EDs;
347
348 fn mul(self, rhs: EDs) -> Self::Output {
349 self.mul(&rhs)
350 }
351}
352
353impl Mul<u64> for &EDs {
354 type Output = EDs;
355
356 fn mul(self, rhs: u64) -> Self::Output {
357 EDs::new(&self.val * BigUint::from(rhs), self.decimals)
358 }
359}
360
361impl Mul<u64> for EDs {
362 type Output = EDs;
363
364 fn mul(self, rhs: u64) -> Self::Output {
365 EDs::new(self.val * BigUint::from(rhs), self.decimals)
366 }
367}
368
369impl MulAssign<&EDs> for EDs {
370 fn mul_assign(&mut self, rhs: &EDs) {
371 if self.decimals != rhs.decimals {
372 unreachable!("Incompatible decimal points");
373 }
374
375 self.val = &self.val * &rhs.val / EDs::base(self.decimals)
376 }
377}
378
379impl MulAssign for EDs {
380 fn mul_assign(&mut self, rhs: Self) {
381 self.mul_assign(&rhs)
382 }
383}
384
385impl MulAssign<u64> for EDs {
386 fn mul_assign(&mut self, rhs: u64) {
387 self.val *= BigUint::from(rhs);
388 }
389}
390
391impl Div for &EDs {
392 type Output = EDs;
393
394 fn div(self, rhs: Self) -> Self::Output {
395 if self.decimals != rhs.decimals {
396 unreachable!("Incompatible decimal points");
397 }
398
399 EDs::new(
400 &self.val * EDs::base(self.decimals) / &rhs.val,
401 self.decimals,
402 )
403 }
404}
405
406impl Div for EDs {
407 type Output = EDs;
408
409 fn div(self, rhs: Self) -> Self::Output {
410 (&self).div(&rhs)
411 }
412}
413
414impl Div<u64> for EDs {
415 type Output = EDs;
416
417 fn div(self, rhs: u64) -> Self::Output {
418 EDs::new(self.val / BigUint::from(rhs), self.decimals)
419 }
420}
421
422impl Div<u64> for &EDs {
423 type Output = EDs;
424
425 fn div(self, rhs: u64) -> Self::Output {
426 EDs::new(&self.val / BigUint::from(rhs), self.decimals)
427 }
428}
429
430impl Div<&EDs> for EDs {
431 type Output = EDs;
432
433 fn div(self, rhs: &EDs) -> Self::Output {
434 (&self).div(rhs)
435 }
436}
437
438impl Div<EDs> for &EDs {
439 type Output = EDs;
440
441 fn div(self, rhs: EDs) -> Self::Output {
442 self.div(&rhs)
443 }
444}
445
446impl DivAssign<&EDs> for EDs {
447 fn div_assign(&mut self, rhs: &EDs) {
448 if self.decimals != rhs.decimals {
449 unreachable!("Incompatible decimal points");
450 }
451
452 *(&mut self.val) = &self.val * EDs::base(self.decimals) / &rhs.val;
453 }
454}
455
456impl DivAssign for EDs {
457 fn div_assign(&mut self, rhs: Self) {
458 self.div_assign(&rhs)
459 }
460}
461
462impl DivAssign<u64> for EDs {
463 fn div_assign(&mut self, rhs: u64) {
464 self.val /= BigUint::from(rhs);
465 }
466}
467
468impl From<(u64, u8)> for EDs {
469 fn from((value, decimals): (u64, u8)) -> Self {
470 Self::new(BigUint::from(value), decimals)
471 }
472}
473
474impl From<(u128, u8)> for EDs {
475 fn from((value, decimals): (u128, u8)) -> Self {
476 Self::new(BigUint::from(value), decimals)
477 }
478}
479
480impl Into<Nat> for EDs {
481 fn into(self) -> Nat {
482 Nat(self.val)
483 }
484}
485
486impl Into<Nat> for &EDs {
487 fn into(self) -> Nat {
488 Nat(self.val.clone())
489 }
490}
491
492#[derive(CandidType, Deserialize)]
493pub struct EDsCandid {
494 pub val: Nat,
495 pub decimals: u8,
496}
497
498impl CandidType for EDs {
499 fn _ty() -> candid::types::Type {
500 EDsCandid::_ty()
501 }
502
503 fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
504 where
505 S: candid::types::Serializer,
506 {
507 (EDsCandid {
508 val: Nat(self.val.clone()),
509 decimals: self.decimals,
510 })
511 .idl_serialize(serializer)
512 }
513}
514
515impl<'de> Deserialize<'de> for EDs {
516 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
517 where
518 D: serde::Deserializer<'de>,
519 {
520 let a = EDsCandid::deserialize(deserializer)?;
521
522 Ok(Self::new(a.val.0, a.decimals))
523 }
524}
525
526impl Storable for EDs {
527 fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
528 let mut val_buf = self.val.to_bytes_le();
529 let len = val_buf.len();
530
531 assert!(len <= 32, "Unable to encode EDs: value too big");
532
533 val_buf.resize(34, 0);
534 val_buf[32] = self.decimals;
535 val_buf[33] = len as u8;
536
537 std::borrow::Cow::Owned(val_buf)
538 }
539
540 fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
541 assert_eq!(
542 bytes.len(),
543 34,
544 "Unable to decode EDs: invalid number of bytes provider"
545 );
546
547 let len = bytes[33];
548 let val = BigUint::from_bytes_le(&bytes[0..len as usize]);
549 let decimals = bytes[32];
550
551 Self { val, decimals }
552 }
553
554 const BOUND: Bound = Bound::Bounded {
555 max_size: 34,
556 is_fixed_size: true,
557 };
558}
559
560#[cfg(test)]
561mod tests {
562 use ic_stable_structures::Storable;
563
564 use super::EDs;
565
566 #[test]
567 fn encoding_works_fine() {
568 let a = EDs::f0_2(7);
569 let a1 = EDs::from_bytes(a.to_bytes());
570 assert_eq!(a, a1);
571
572 let b = EDs::one(8);
573 let b1 = EDs::from_bytes(b.to_bytes());
574 assert_eq!(b, b1);
575
576 let c = EDs::from((u128::MAX, 31));
577 let c1 = EDs::from_bytes(c.to_bytes());
578 assert_eq!(c, c1);
579
580 let d = EDs::from((u64::MAX, 31));
581 let d1 = EDs::from_bytes(d.to_bytes());
582 assert_eq!(d, d1);
583 }
584}