soroban_sdk/
num.rs

1use core::{cmp::Ordering, convert::Infallible, fmt::Debug};
2
3use super::{
4    env::internal::{
5        DurationSmall, DurationVal, Env as _, EnvBase as _, I256Small, I256Val, TimepointSmall,
6        TimepointVal, 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        env.check_same_env(bytes.env()).unwrap_infallible();
221        let val = env
222            .u256_val_from_be_bytes(bytes.to_object())
223            .unwrap_infallible();
224        U256 {
225            env: env.clone(),
226            val,
227        }
228    }
229
230    pub fn to_u128(&self) -> Option<u128> {
231        let be_bytes = self.to_be_bytes();
232        let be_bytes_hi: [u8; 16] = be_bytes.slice(0..16).try_into().unwrap();
233        let be_bytes_lo: [u8; 16] = be_bytes.slice(16..32).try_into().unwrap();
234        if u128::from_be_bytes(be_bytes_hi) == 0 {
235            Some(u128::from_be_bytes(be_bytes_lo))
236        } else {
237            None
238        }
239    }
240
241    pub fn to_be_bytes(&self) -> Bytes {
242        let obj = self
243            .env
244            .u256_val_to_be_bytes(self.to_val_type())
245            .unwrap_infallible();
246        unsafe { Bytes::unchecked_new(self.env.clone(), obj) }
247    }
248
249    pub fn add(&self, other: &U256) -> U256 {
250        self.env.check_same_env(&other.env).unwrap_infallible();
251        let val = self.env.u256_add(self.val, other.val).unwrap_infallible();
252        U256 {
253            env: self.env.clone(),
254            val,
255        }
256    }
257
258    pub fn sub(&self, other: &U256) -> U256 {
259        self.env.check_same_env(&other.env).unwrap_infallible();
260        let val = self.env.u256_sub(self.val, other.val).unwrap_infallible();
261        U256 {
262            env: self.env.clone(),
263            val,
264        }
265    }
266
267    pub fn mul(&self, other: &U256) -> U256 {
268        self.env.check_same_env(&other.env).unwrap_infallible();
269        let val = self.env.u256_mul(self.val, other.val).unwrap_infallible();
270        U256 {
271            env: self.env.clone(),
272            val,
273        }
274    }
275
276    pub fn div(&self, other: &U256) -> U256 {
277        self.env.check_same_env(&other.env).unwrap_infallible();
278        let val = self.env.u256_div(self.val, other.val).unwrap_infallible();
279        U256 {
280            env: self.env.clone(),
281            val,
282        }
283    }
284
285    pub fn rem_euclid(&self, other: &U256) -> U256 {
286        self.env.check_same_env(&other.env).unwrap_infallible();
287        let val = self
288            .env
289            .u256_rem_euclid(self.val, other.val)
290            .unwrap_infallible();
291        U256 {
292            env: self.env.clone(),
293            val,
294        }
295    }
296
297    pub fn pow(&self, pow: u32) -> U256 {
298        let val = self.env.u256_pow(self.val, pow.into()).unwrap_infallible();
299        U256 {
300            env: self.env.clone(),
301            val,
302        }
303    }
304
305    pub fn shl(&self, bits: u32) -> U256 {
306        let val = self.env.u256_shl(self.val, bits.into()).unwrap_infallible();
307        U256 {
308            env: self.env.clone(),
309            val,
310        }
311    }
312
313    pub fn shr(&self, bits: u32) -> U256 {
314        let val = self.env.u256_shr(self.val, bits.into()).unwrap_infallible();
315        U256 {
316            env: self.env.clone(),
317            val,
318        }
319    }
320}
321
322/// I256 holds a 256-bit signed integer.
323///
324/// ### Examples
325///
326/// ```
327/// use soroban_sdk::{I256, Env};
328///
329/// let env = Env::default();
330///
331/// let i1 = I256::from_i32(&env, -6);
332/// let i2 = I256::from_i32(&env, 3);
333/// assert_eq!(i1.add(&i2), I256::from_i32(&env, -3));
334/// ```
335#[derive(Clone)]
336pub struct I256 {
337    env: Env,
338    val: I256Val,
339}
340
341impl_num_wrapping_val_type!(I256, I256Val, I256Small);
342
343impl I256 {
344    pub fn from_i32(env: &Env, i: i32) -> Self {
345        I256 {
346            env: env.clone(),
347            val: I256Val::from_i32(i),
348        }
349    }
350
351    pub fn from_i128(env: &Env, i: i128) -> Self {
352        let lo: Bytes = Bytes::from_array(env, &i.to_be_bytes());
353        if i < 0 {
354            let mut i256_bytes: Bytes = Bytes::from_array(env, &[255_u8; 16]);
355            i256_bytes.append(&lo);
356            Self::from_be_bytes(env, &i256_bytes)
357        } else {
358            let mut i256_bytes: Bytes = Bytes::from_array(env, &[0_u8; 16]);
359            i256_bytes.append(&lo);
360            Self::from_be_bytes(env, &i256_bytes)
361        }
362    }
363
364    pub fn from_parts(env: &Env, hi_hi: i64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self {
365        let obj = env
366            .obj_from_i256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
367            .unwrap_infallible();
368        I256 {
369            env: env.clone(),
370            val: obj.into(),
371        }
372    }
373
374    pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self {
375        env.check_same_env(bytes.env()).unwrap_infallible();
376        let val = env
377            .i256_val_from_be_bytes(bytes.to_object())
378            .unwrap_infallible();
379        I256 {
380            env: env.clone(),
381            val,
382        }
383    }
384
385    pub fn to_i128(&self) -> Option<i128> {
386        let be_bytes = self.to_be_bytes();
387        let be_bytes_hi: [u8; 16] = be_bytes.slice(0..16).try_into().unwrap();
388        let be_bytes_lo: [u8; 16] = be_bytes.slice(16..32).try_into().unwrap();
389        let i128_hi = i128::from_be_bytes(be_bytes_hi);
390        let i128_lo = i128::from_be_bytes(be_bytes_lo);
391        if (i128_hi == 0 && i128_lo >= 0) || (i128_hi == -1 && i128_lo < 0) {
392            Some(i128_lo)
393        } else {
394            None
395        }
396    }
397
398    pub fn to_be_bytes(&self) -> Bytes {
399        let obj = self
400            .env
401            .i256_val_to_be_bytes(self.to_val_type())
402            .unwrap_infallible();
403        unsafe { Bytes::unchecked_new(self.env.clone(), obj) }
404    }
405
406    pub fn add(&self, other: &I256) -> I256 {
407        self.env.check_same_env(&other.env).unwrap_infallible();
408        let val = self.env.i256_add(self.val, other.val).unwrap_infallible();
409        I256 {
410            env: self.env.clone(),
411            val,
412        }
413    }
414
415    pub fn sub(&self, other: &I256) -> I256 {
416        self.env.check_same_env(&other.env).unwrap_infallible();
417        let val = self.env.i256_sub(self.val, other.val).unwrap_infallible();
418        I256 {
419            env: self.env.clone(),
420            val,
421        }
422    }
423
424    pub fn mul(&self, other: &I256) -> I256 {
425        self.env.check_same_env(&other.env).unwrap_infallible();
426        let val = self.env.i256_mul(self.val, other.val).unwrap_infallible();
427        I256 {
428            env: self.env.clone(),
429            val,
430        }
431    }
432
433    pub fn div(&self, other: &I256) -> I256 {
434        self.env.check_same_env(&other.env).unwrap_infallible();
435        let val = self.env.i256_div(self.val, other.val).unwrap_infallible();
436        I256 {
437            env: self.env.clone(),
438            val,
439        }
440    }
441
442    pub fn rem_euclid(&self, other: &I256) -> I256 {
443        self.env.check_same_env(&other.env).unwrap_infallible();
444        let val = self
445            .env
446            .i256_rem_euclid(self.val, other.val)
447            .unwrap_infallible();
448        I256 {
449            env: self.env.clone(),
450            val,
451        }
452    }
453
454    pub fn pow(&self, pow: u32) -> I256 {
455        let val = self.env.i256_pow(self.val, pow.into()).unwrap_infallible();
456        I256 {
457            env: self.env.clone(),
458            val,
459        }
460    }
461
462    pub fn shl(&self, bits: u32) -> I256 {
463        let val = self.env.i256_shl(self.val, bits.into()).unwrap_infallible();
464        I256 {
465            env: self.env.clone(),
466            val,
467        }
468    }
469
470    pub fn shr(&self, bits: u32) -> I256 {
471        let val = self.env.i256_shr(self.val, bits.into()).unwrap_infallible();
472        I256 {
473            env: self.env.clone(),
474            val,
475        }
476    }
477}
478
479#[doc = "Timepoint holds a 64-bit unsigned integer."]
480#[derive(Clone)]
481pub struct Timepoint {
482    env: Env,
483    val: TimepointVal,
484}
485
486impl_num_wrapping_val_type!(Timepoint, TimepointVal, TimepointSmall);
487
488impl Timepoint {
489    /// Create a Timepoint from a unix time in seconds, the time in seconds
490    /// since January 1, 1970 UTC.
491    pub fn from_unix(env: &Env, seconds: u64) -> Timepoint {
492        let val = TimepointVal::try_from_val(env, &seconds).unwrap_optimized();
493        Timepoint {
494            env: env.clone(),
495            val,
496        }
497    }
498
499    /// Returns the Timepoint as unix time in seconds, the time in seconds since
500    /// January 1, 1970 UTC.
501    pub fn to_unix(&self) -> u64 {
502        u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized()
503    }
504}
505
506#[doc = "Duration holds a 64-bit unsigned integer."]
507#[derive(Clone)]
508pub struct Duration {
509    env: Env,
510    val: DurationVal,
511}
512
513impl_num_wrapping_val_type!(Duration, DurationVal, DurationSmall);
514
515impl Duration {
516    /// Create a Duration from seconds.
517    pub fn from_seconds(env: &Env, seconds: u64) -> Duration {
518        let val = DurationVal::try_from_val(env, &seconds).unwrap_optimized();
519        Duration {
520            env: env.clone(),
521            val,
522        }
523    }
524
525    /// Returns the Duration as seconds.
526    pub fn to_seconds(&self) -> u64 {
527        u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized()
528    }
529}
530
531#[cfg(test)]
532mod test {
533    use super::*;
534
535    #[test]
536    fn test_u256_roundtrip() {
537        let env = Env::default();
538
539        let u1 = U256::from_u32(&env, 12345);
540        let bytes = u1.to_be_bytes();
541        let u2 = U256::from_be_bytes(&env, &bytes);
542        assert_eq!(u1, u2);
543    }
544
545    #[test]
546    fn test_u256_u128_conversion() {
547        let env = Env::default();
548
549        // positive
550        let start = u128::MAX / 7;
551        let from = U256::from_u128(&env, start);
552        let end = from.to_u128().unwrap();
553        assert_eq!(start, end);
554
555        let over_u128 = from.mul(&U256::from_u32(&env, 8));
556        let failure = over_u128.to_u128();
557        assert_eq!(failure, None);
558
559        // zero
560        let start = 0_u128;
561        let from = U256::from_u128(&env, start);
562        let end = from.to_u128().unwrap();
563        assert_eq!(start, end);
564    }
565
566    #[test]
567    fn test_i256_roundtrip() {
568        let env = Env::default();
569
570        let i1 = I256::from_i32(&env, -12345);
571        let bytes = i1.to_be_bytes();
572        let i2 = I256::from_be_bytes(&env, &bytes);
573        assert_eq!(i1, i2);
574    }
575
576    #[test]
577    fn test_i256_i128_conversion() {
578        let env = Env::default();
579
580        // positive
581        let start = i128::MAX / 7;
582        let from = I256::from_i128(&env, start);
583        let end = from.to_i128().unwrap();
584        assert_eq!(start, end);
585
586        let over_i128 = from.mul(&I256::from_i32(&env, 8));
587        let failure = over_i128.to_i128();
588        assert_eq!(failure, None);
589
590        // negative
591        let start = i128::MIN / 7;
592        let from = I256::from_i128(&env, start);
593        let end = from.to_i128().unwrap();
594        assert_eq!(start, end);
595
596        let over_i128 = from.mul(&I256::from_i32(&env, 8));
597        let failure = over_i128.to_i128();
598        assert_eq!(failure, None);
599
600        // zero
601        let start = 0_i128;
602        let from = I256::from_i128(&env, start);
603        let end = from.to_i128().unwrap();
604        assert_eq!(start, end);
605    }
606
607    #[test]
608    fn test_timepoint_roundtrip() {
609        let env = Env::default();
610
611        let tp = Timepoint::from_unix(&env, 123);
612        let u = tp.to_unix();
613        assert_eq!(u, 123);
614    }
615
616    #[test]
617    fn test_duration_roundtrip() {
618        let env = Env::default();
619
620        let tp = Duration::from_seconds(&env, 123);
621        let u = tp.to_seconds();
622        assert_eq!(u, 123);
623    }
624
625    #[test]
626    fn test_u256_arith() {
627        let env = Env::default();
628
629        let u1 = U256::from_u32(&env, 6);
630        let u2 = U256::from_u32(&env, 3);
631        assert_eq!(u1.add(&u2), U256::from_u32(&env, 9));
632        assert_eq!(u1.sub(&u2), U256::from_u32(&env, 3));
633        assert_eq!(u1.mul(&u2), U256::from_u32(&env, 18));
634        assert_eq!(u1.div(&u2), U256::from_u32(&env, 2));
635        assert_eq!(u1.pow(2), U256::from_u32(&env, 36));
636        assert_eq!(u1.shl(2), U256::from_u32(&env, 24));
637        assert_eq!(u1.shr(1), U256::from_u32(&env, 3));
638
639        let u3 = U256::from_u32(&env, 7);
640        let u4 = U256::from_u32(&env, 4);
641        assert_eq!(u3.rem_euclid(&u4), U256::from_u32(&env, 3));
642    }
643
644    #[test]
645    fn test_i256_arith() {
646        let env = Env::default();
647
648        let i1 = I256::from_i32(&env, -6);
649        let i2 = I256::from_i32(&env, 3);
650        assert_eq!(i1.add(&i2), I256::from_i32(&env, -3));
651        assert_eq!(i1.sub(&i2), I256::from_i32(&env, -9));
652        assert_eq!(i1.mul(&i2), I256::from_i32(&env, -18));
653        assert_eq!(i1.div(&i2), I256::from_i32(&env, -2));
654        assert_eq!(i1.pow(2), I256::from_i32(&env, 36));
655        assert_eq!(i1.shl(2), I256::from_i32(&env, -24));
656        assert_eq!(i1.shr(1), I256::from_i32(&env, -3));
657
658        let u3 = I256::from_i32(&env, -7);
659        let u4 = I256::from_i32(&env, 4);
660        assert_eq!(u3.rem_euclid(&u4), I256::from_i32(&env, 1));
661    }
662}