soroban_sdk/
num.rs

1use core::{cmp::Ordering, convert::Infallible, fmt::Debug};
2
3use super::{
4    env::internal::{
5        DurationSmall, DurationVal, Env as _, I256Small, I256Val, TimepointSmall, TimepointVal,
6        U256Small, U256Val,
7    },
8    Bytes, ConversionError, Env, TryFromVal, TryIntoVal, Val,
9};
10
11#[cfg(not(target_family = "wasm"))]
12use crate::env::internal::xdr::ScVal;
13use crate::unwrap::{UnwrapInfallible, UnwrapOptimized};
14
15macro_rules! impl_num_wrapping_val_type {
16    ($wrapper:ident, $val:ty, $small:ty) => {
17        impl Debug for $wrapper {
18            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19                // FIXME: properly print it when we have the conversion functions
20                write!(f, "{:?}", self.val.as_val())
21            }
22        }
23
24        impl Eq for $wrapper {}
25
26        impl PartialEq for $wrapper {
27            fn eq(&self, other: &Self) -> bool {
28                self.partial_cmp(other) == Some(Ordering::Equal)
29            }
30        }
31
32        impl PartialOrd for $wrapper {
33            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
34                Some(Ord::cmp(self, other))
35            }
36        }
37
38        impl Ord for $wrapper {
39            fn cmp(&self, other: &Self) -> Ordering {
40                let self_raw = self.val.to_val();
41                let other_raw = other.val.to_val();
42
43                match (<$small>::try_from(self_raw), <$small>::try_from(other_raw)) {
44                    // Compare small numbers.
45                    (Ok(self_num), Ok(other_num)) => self_num.cmp(&other_num),
46                    // The object-to-small number comparisons are handled by `obj_cmp`,
47                    // so it's safe to handle all the other cases using it.
48                    _ => {
49                        #[cfg(not(target_family = "wasm"))]
50                        if !self.env.is_same_env(&other.env) {
51                            return ScVal::from(self).cmp(&ScVal::from(other));
52                        }
53                        let v = self.env.obj_cmp(self_raw, other_raw).unwrap_infallible();
54                        v.cmp(&0)
55                    }
56                }
57            }
58        }
59
60        impl From<$wrapper> for $val {
61            #[inline(always)]
62            fn from(v: $wrapper) -> Self {
63                v.val
64            }
65        }
66
67        impl From<&$wrapper> for $val {
68            #[inline(always)]
69            fn from(v: &$wrapper) -> Self {
70                v.val
71            }
72        }
73
74        impl From<&$wrapper> for $wrapper {
75            #[inline(always)]
76            fn from(v: &$wrapper) -> Self {
77                v.clone()
78            }
79        }
80
81        impl TryFromVal<Env, $val> for $wrapper {
82            type Error = Infallible;
83
84            fn try_from_val(env: &Env, val: &$val) -> Result<Self, Self::Error> {
85                Ok(unsafe { $wrapper::unchecked_new(env.clone(), *val) })
86            }
87        }
88
89        impl TryFromVal<Env, Val> for $wrapper {
90            type Error = ConversionError;
91
92            fn try_from_val(env: &Env, val: &Val) -> Result<Self, Self::Error> {
93                Ok(<$val>::try_from_val(env, val)?
94                    .try_into_val(env)
95                    .unwrap_infallible())
96            }
97        }
98
99        impl TryFromVal<Env, $wrapper> for Val {
100            type Error = ConversionError;
101
102            fn try_from_val(_env: &Env, v: &$wrapper) -> Result<Self, Self::Error> {
103                Ok(v.to_val())
104            }
105        }
106
107        impl TryFromVal<Env, &$wrapper> for Val {
108            type Error = ConversionError;
109
110            fn try_from_val(_env: &Env, v: &&$wrapper) -> Result<Self, Self::Error> {
111                Ok(v.to_val())
112            }
113        }
114
115        #[cfg(not(target_family = "wasm"))]
116        impl From<&$wrapper> for ScVal {
117            fn from(v: &$wrapper) -> Self {
118                // This conversion occurs only in test utilities, and theoretically all
119                // values should convert to an ScVal because the Env won't let the host
120                // type to exist otherwise, unwrapping. Even if there are edge cases
121                // that don't, this is a trade off for a better test developer
122                // experience.
123                if let Ok(ss) = <$small>::try_from(v.val) {
124                    ScVal::try_from(ss).unwrap()
125                } else {
126                    ScVal::try_from_val(&v.env, &v.to_val()).unwrap()
127                }
128            }
129        }
130
131        #[cfg(not(target_family = "wasm"))]
132        impl From<$wrapper> for ScVal {
133            fn from(v: $wrapper) -> Self {
134                (&v).into()
135            }
136        }
137
138        #[cfg(not(target_family = "wasm"))]
139        impl TryFromVal<Env, ScVal> for $wrapper {
140            type Error = ConversionError;
141            fn try_from_val(env: &Env, val: &ScVal) -> Result<Self, Self::Error> {
142                Ok(<$val>::try_from_val(env, &Val::try_from_val(env, val)?)?
143                    .try_into_val(env)
144                    .unwrap_infallible())
145            }
146        }
147
148        impl $wrapper {
149            #[inline(always)]
150            pub(crate) unsafe fn unchecked_new(env: Env, val: $val) -> Self {
151                Self { env, val }
152            }
153
154            #[inline(always)]
155            pub fn env(&self) -> &Env {
156                &self.env
157            }
158
159            pub fn as_val(&self) -> &Val {
160                self.val.as_val()
161            }
162
163            pub fn to_val(&self) -> Val {
164                self.val.to_val()
165            }
166
167            pub fn to_val_type(&self) -> $val {
168                self.val
169            }
170        }
171    };
172}
173
174/// U256 holds a 256-bit unsigned integer.
175///
176/// ### Examples
177///
178/// ```
179/// use soroban_sdk::{U256, Env};
180///
181/// let env = Env::default();
182/// let u1 = U256::from_u32(&env, 6);
183/// let u2 = U256::from_u32(&env, 3);
184/// assert_eq!(u1.add(&u2), U256::from_u32(&env, 9));
185/// ```
186#[derive(Clone)]
187pub struct U256 {
188    env: Env,
189    val: U256Val,
190}
191
192impl_num_wrapping_val_type!(U256, U256Val, U256Small);
193
194impl U256 {
195    pub fn from_u32(env: &Env, u: u32) -> Self {
196        U256 {
197            env: env.clone(),
198            val: U256Val::from_u32(u),
199        }
200    }
201
202    pub fn from_u128(env: &Env, u: u128) -> Self {
203        let lo: Bytes = Bytes::from_array(env, &u.to_be_bytes());
204        let mut bytes: Bytes = Bytes::from_array(env, &[0u8; 16]);
205        bytes.append(&lo);
206        Self::from_be_bytes(env, &bytes)
207    }
208
209    pub fn from_parts(env: &Env, hi_hi: u64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self {
210        let obj = env
211            .obj_from_u256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
212            .unwrap_infallible();
213        U256 {
214            env: env.clone(),
215            val: obj.into(),
216        }
217    }
218
219    pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self {
220        let val = env
221            .u256_val_from_be_bytes(bytes.to_object())
222            .unwrap_infallible();
223        U256 {
224            env: env.clone(),
225            val,
226        }
227    }
228
229    pub fn to_u128(&self) -> Option<u128> {
230        let be_bytes = self.to_be_bytes();
231        let be_bytes_hi: [u8; 16] = be_bytes.slice(0..16).try_into().unwrap();
232        let be_bytes_lo: [u8; 16] = be_bytes.slice(16..32).try_into().unwrap();
233        if u128::from_be_bytes(be_bytes_hi) == 0 {
234            Some(u128::from_be_bytes(be_bytes_lo))
235        } else {
236            None
237        }
238    }
239
240    pub fn to_be_bytes(&self) -> Bytes {
241        let obj = self
242            .env
243            .u256_val_to_be_bytes(self.to_val_type())
244            .unwrap_infallible();
245        unsafe { Bytes::unchecked_new(self.env.clone(), obj) }
246    }
247
248    pub fn add(&self, other: &U256) -> U256 {
249        let val = self.env.u256_add(self.val, other.val).unwrap_infallible();
250        U256 {
251            env: self.env.clone(),
252            val,
253        }
254    }
255
256    pub fn sub(&self, other: &U256) -> U256 {
257        let val = self.env.u256_sub(self.val, other.val).unwrap_infallible();
258        U256 {
259            env: self.env.clone(),
260            val,
261        }
262    }
263
264    pub fn mul(&self, other: &U256) -> U256 {
265        let val = self.env.u256_mul(self.val, other.val).unwrap_infallible();
266        U256 {
267            env: self.env.clone(),
268            val,
269        }
270    }
271
272    pub fn div(&self, other: &U256) -> U256 {
273        let val = self.env.u256_div(self.val, other.val).unwrap_infallible();
274        U256 {
275            env: self.env.clone(),
276            val,
277        }
278    }
279
280    pub fn rem_euclid(&self, other: &U256) -> U256 {
281        let val = self
282            .env
283            .u256_rem_euclid(self.val, other.val)
284            .unwrap_infallible();
285        U256 {
286            env: self.env.clone(),
287            val,
288        }
289    }
290
291    pub fn pow(&self, pow: u32) -> U256 {
292        let val = self.env.u256_pow(self.val, pow.into()).unwrap_infallible();
293        U256 {
294            env: self.env.clone(),
295            val,
296        }
297    }
298
299    pub fn shl(&self, bits: u32) -> U256 {
300        let val = self.env.u256_shl(self.val, bits.into()).unwrap_infallible();
301        U256 {
302            env: self.env.clone(),
303            val,
304        }
305    }
306
307    pub fn shr(&self, bits: u32) -> U256 {
308        let val = self.env.u256_shr(self.val, bits.into()).unwrap_infallible();
309        U256 {
310            env: self.env.clone(),
311            val,
312        }
313    }
314}
315
316/// I256 holds a 256-bit signed integer.
317///
318/// ### Examples
319///
320/// ```
321/// use soroban_sdk::{I256, Env};
322///
323/// let env = Env::default();
324///
325/// let i1 = I256::from_i32(&env, -6);
326/// let i2 = I256::from_i32(&env, 3);
327/// assert_eq!(i1.add(&i2), I256::from_i32(&env, -3));
328/// ```
329#[derive(Clone)]
330pub struct I256 {
331    env: Env,
332    val: I256Val,
333}
334
335impl_num_wrapping_val_type!(I256, I256Val, I256Small);
336
337impl I256 {
338    pub fn from_i32(env: &Env, i: i32) -> Self {
339        I256 {
340            env: env.clone(),
341            val: I256Val::from_i32(i),
342        }
343    }
344
345    pub fn from_i128(env: &Env, i: i128) -> Self {
346        let lo: Bytes = Bytes::from_array(env, &i.to_be_bytes());
347        if i < 0 {
348            let mut i256_bytes: Bytes = Bytes::from_array(env, &[255_u8; 16]);
349            i256_bytes.append(&lo);
350            Self::from_be_bytes(env, &i256_bytes)
351        } else {
352            let mut i256_bytes: Bytes = Bytes::from_array(env, &[0_u8; 16]);
353            i256_bytes.append(&lo);
354            Self::from_be_bytes(env, &i256_bytes)
355        }
356    }
357
358    pub fn from_parts(env: &Env, hi_hi: i64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self {
359        let obj = env
360            .obj_from_i256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
361            .unwrap_infallible();
362        I256 {
363            env: env.clone(),
364            val: obj.into(),
365        }
366    }
367
368    pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self {
369        let val = env
370            .i256_val_from_be_bytes(bytes.to_object())
371            .unwrap_infallible();
372        I256 {
373            env: env.clone(),
374            val,
375        }
376    }
377
378    pub fn to_i128(&self) -> Option<i128> {
379        let be_bytes = self.to_be_bytes();
380        let be_bytes_hi: [u8; 16] = be_bytes.slice(0..16).try_into().unwrap();
381        let be_bytes_lo: [u8; 16] = be_bytes.slice(16..32).try_into().unwrap();
382        let i128_hi = i128::from_be_bytes(be_bytes_hi);
383        let i128_lo = i128::from_be_bytes(be_bytes_lo);
384        if (i128_hi == 0 && i128_lo >= 0) || (i128_hi == -1 && i128_lo < 0) {
385            Some(i128_lo)
386        } else {
387            None
388        }
389    }
390
391    pub fn to_be_bytes(&self) -> Bytes {
392        let obj = self
393            .env
394            .i256_val_to_be_bytes(self.to_val_type())
395            .unwrap_infallible();
396        unsafe { Bytes::unchecked_new(self.env.clone(), obj) }
397    }
398
399    pub fn add(&self, other: &I256) -> I256 {
400        let val = self.env.i256_add(self.val, other.val).unwrap_infallible();
401        I256 {
402            env: self.env.clone(),
403            val,
404        }
405    }
406
407    pub fn sub(&self, other: &I256) -> I256 {
408        let val = self.env.i256_sub(self.val, other.val).unwrap_infallible();
409        I256 {
410            env: self.env.clone(),
411            val,
412        }
413    }
414
415    pub fn mul(&self, other: &I256) -> I256 {
416        let val = self.env.i256_mul(self.val, other.val).unwrap_infallible();
417        I256 {
418            env: self.env.clone(),
419            val,
420        }
421    }
422
423    pub fn div(&self, other: &I256) -> I256 {
424        let val = self.env.i256_div(self.val, other.val).unwrap_infallible();
425        I256 {
426            env: self.env.clone(),
427            val,
428        }
429    }
430
431    pub fn rem_euclid(&self, other: &I256) -> I256 {
432        let val = self
433            .env
434            .i256_rem_euclid(self.val, other.val)
435            .unwrap_infallible();
436        I256 {
437            env: self.env.clone(),
438            val,
439        }
440    }
441
442    pub fn pow(&self, pow: u32) -> I256 {
443        let val = self.env.i256_pow(self.val, pow.into()).unwrap_infallible();
444        I256 {
445            env: self.env.clone(),
446            val,
447        }
448    }
449
450    pub fn shl(&self, bits: u32) -> I256 {
451        let val = self.env.i256_shl(self.val, bits.into()).unwrap_infallible();
452        I256 {
453            env: self.env.clone(),
454            val,
455        }
456    }
457
458    pub fn shr(&self, bits: u32) -> I256 {
459        let val = self.env.i256_shr(self.val, bits.into()).unwrap_infallible();
460        I256 {
461            env: self.env.clone(),
462            val,
463        }
464    }
465}
466
467#[doc = "Timepoint holds a 64-bit unsigned integer."]
468#[derive(Clone)]
469pub struct Timepoint {
470    env: Env,
471    val: TimepointVal,
472}
473
474impl_num_wrapping_val_type!(Timepoint, TimepointVal, TimepointSmall);
475
476impl Timepoint {
477    /// Create a Timepoint from a unix time in seconds, the time in seconds
478    /// since January 1, 1970 UTC.
479    pub fn from_unix(env: &Env, seconds: u64) -> Timepoint {
480        let val = TimepointVal::try_from_val(env, &seconds).unwrap_optimized();
481        Timepoint {
482            env: env.clone(),
483            val,
484        }
485    }
486
487    /// Returns the Timepoint as unix time in seconds, the time in seconds since
488    /// January 1, 1970 UTC.
489    pub fn to_unix(&self) -> u64 {
490        u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized()
491    }
492}
493
494#[doc = "Duration holds a 64-bit unsigned integer."]
495#[derive(Clone)]
496pub struct Duration {
497    env: Env,
498    val: DurationVal,
499}
500
501impl_num_wrapping_val_type!(Duration, DurationVal, DurationSmall);
502
503impl Duration {
504    /// Create a Duration from seconds.
505    pub fn from_seconds(env: &Env, seconds: u64) -> Duration {
506        let val = DurationVal::try_from_val(env, &seconds).unwrap_optimized();
507        Duration {
508            env: env.clone(),
509            val,
510        }
511    }
512
513    /// Returns the Duration as seconds.
514    pub fn to_seconds(&self) -> u64 {
515        u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized()
516    }
517}
518
519#[cfg(test)]
520mod test {
521    use super::*;
522
523    #[test]
524    fn test_u256_roundtrip() {
525        let env = Env::default();
526
527        let u1 = U256::from_u32(&env, 12345);
528        let bytes = u1.to_be_bytes();
529        let u2 = U256::from_be_bytes(&env, &bytes);
530        assert_eq!(u1, u2);
531    }
532
533    #[test]
534    fn test_u256_u128_conversion() {
535        let env = Env::default();
536
537        // positive
538        let start = u128::MAX / 7;
539        let from = U256::from_u128(&env, start);
540        let end = from.to_u128().unwrap();
541        assert_eq!(start, end);
542
543        let over_u128 = from.mul(&U256::from_u32(&env, 8));
544        let failure = over_u128.to_u128();
545        assert_eq!(failure, None);
546
547        // zero
548        let start = 0_u128;
549        let from = U256::from_u128(&env, start);
550        let end = from.to_u128().unwrap();
551        assert_eq!(start, end);
552    }
553
554    #[test]
555    fn test_i256_roundtrip() {
556        let env = Env::default();
557
558        let i1 = I256::from_i32(&env, -12345);
559        let bytes = i1.to_be_bytes();
560        let i2 = I256::from_be_bytes(&env, &bytes);
561        assert_eq!(i1, i2);
562    }
563
564    #[test]
565    fn test_i256_i128_conversion() {
566        let env = Env::default();
567
568        // positive
569        let start = i128::MAX / 7;
570        let from = I256::from_i128(&env, start);
571        let end = from.to_i128().unwrap();
572        assert_eq!(start, end);
573
574        let over_i128 = from.mul(&I256::from_i32(&env, 8));
575        let failure = over_i128.to_i128();
576        assert_eq!(failure, None);
577
578        // negative
579        let start = i128::MIN / 7;
580        let from = I256::from_i128(&env, start);
581        let end = from.to_i128().unwrap();
582        assert_eq!(start, end);
583
584        let over_i128 = from.mul(&I256::from_i32(&env, 8));
585        let failure = over_i128.to_i128();
586        assert_eq!(failure, None);
587
588        // zero
589        let start = 0_i128;
590        let from = I256::from_i128(&env, start);
591        let end = from.to_i128().unwrap();
592        assert_eq!(start, end);
593    }
594
595    #[test]
596    fn test_timepoint_roundtrip() {
597        let env = Env::default();
598
599        let tp = Timepoint::from_unix(&env, 123);
600        let u = tp.to_unix();
601        assert_eq!(u, 123);
602    }
603
604    #[test]
605    fn test_duration_roundtrip() {
606        let env = Env::default();
607
608        let tp = Duration::from_seconds(&env, 123);
609        let u = tp.to_seconds();
610        assert_eq!(u, 123);
611    }
612
613    #[test]
614    fn test_u256_arith() {
615        let env = Env::default();
616
617        let u1 = U256::from_u32(&env, 6);
618        let u2 = U256::from_u32(&env, 3);
619        assert_eq!(u1.add(&u2), U256::from_u32(&env, 9));
620        assert_eq!(u1.sub(&u2), U256::from_u32(&env, 3));
621        assert_eq!(u1.mul(&u2), U256::from_u32(&env, 18));
622        assert_eq!(u1.div(&u2), U256::from_u32(&env, 2));
623        assert_eq!(u1.pow(2), U256::from_u32(&env, 36));
624        assert_eq!(u1.shl(2), U256::from_u32(&env, 24));
625        assert_eq!(u1.shr(1), U256::from_u32(&env, 3));
626
627        let u3 = U256::from_u32(&env, 7);
628        let u4 = U256::from_u32(&env, 4);
629        assert_eq!(u3.rem_euclid(&u4), U256::from_u32(&env, 3));
630    }
631
632    #[test]
633    fn test_i256_arith() {
634        let env = Env::default();
635
636        let i1 = I256::from_i32(&env, -6);
637        let i2 = I256::from_i32(&env, 3);
638        assert_eq!(i1.add(&i2), I256::from_i32(&env, -3));
639        assert_eq!(i1.sub(&i2), I256::from_i32(&env, -9));
640        assert_eq!(i1.mul(&i2), I256::from_i32(&env, -18));
641        assert_eq!(i1.div(&i2), I256::from_i32(&env, -2));
642        assert_eq!(i1.pow(2), I256::from_i32(&env, 36));
643        assert_eq!(i1.shl(2), I256::from_i32(&env, -24));
644        assert_eq!(i1.shr(1), I256::from_i32(&env, -3));
645
646        let u3 = I256::from_i32(&env, -7);
647        let u4 = I256::from_i32(&env, 4);
648        assert_eq!(u3.rem_euclid(&u4), I256::from_i32(&env, 1));
649    }
650}