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