Skip to main content

soroban_sdk/
num.rs

1use core::{cmp::Ordering, convert::Infallible, fmt::Debug};
2
3use super::{
4    env::internal::{
5        DurationSmall, DurationVal, Env as _, I256Object, I256Small, I256Val, TimepointSmall,
6        TimepointVal, U256Object, 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            /// Converts a `Val` known to be of this type into `Self` without
155            /// env-based conversion. The caller must guarantee the `Val` is of
156            /// the correct type; only a cheap tag check is performed.
157            #[inline(always)]
158            pub(crate) unsafe fn unchecked_from_val(env: Env, val: Val) -> Self {
159                Self {
160                    env,
161                    val: <$val>::try_from(val).unwrap_optimized(),
162                }
163            }
164
165            #[inline(always)]
166            pub fn env(&self) -> &Env {
167                &self.env
168            }
169
170            pub fn as_val(&self) -> &Val {
171                self.val.as_val()
172            }
173
174            pub fn to_val(&self) -> Val {
175                self.val.to_val()
176            }
177
178            pub fn to_val_type(&self) -> $val {
179                self.val
180            }
181        }
182    };
183}
184
185/// U256 holds a 256-bit unsigned integer.
186///
187/// ### Examples
188///
189/// ```
190/// use soroban_sdk::{U256, Env};
191///
192/// let env = Env::default();
193/// let u1 = U256::from_u32(&env, 6);
194/// let u2 = U256::from_u32(&env, 3);
195/// assert_eq!(u1.add(&u2), U256::from_u32(&env, 9));
196/// ```
197#[derive(Clone)]
198pub struct U256 {
199    env: Env,
200    val: U256Val,
201}
202
203impl_num_wrapping_val_type!(U256, U256Val, U256Small);
204
205impl U256 {
206    pub const BITS: u32 = 256;
207
208    /// Returns the smallest value that can be represented by this type (0).
209    pub fn min_value(env: &Env) -> Self {
210        Self::from_u32(env, 0)
211    }
212
213    /// Returns the largest value that can be represented by this type (2^256 - 1).
214    pub fn max_value(env: &Env) -> Self {
215        Self::from_parts(env, u64::MAX, u64::MAX, u64::MAX, u64::MAX)
216    }
217
218    fn is_zero(&self) -> bool {
219        *self == U256::from_u32(&self.env, 0)
220    }
221
222    pub fn from_u32(env: &Env, u: u32) -> Self {
223        U256 {
224            env: env.clone(),
225            val: U256Val::from_u32(u),
226        }
227    }
228
229    pub fn from_u128(env: &Env, u: u128) -> Self {
230        let lo_hi = (u >> 64) as u64;
231        let lo_lo = u as u64;
232        Self::from_parts(env, 0, 0, lo_hi, lo_lo)
233    }
234
235    pub fn from_parts(env: &Env, hi_hi: u64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self {
236        let obj = env
237            .obj_from_u256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
238            .unwrap_infallible();
239        U256 {
240            env: env.clone(),
241            val: obj.into(),
242        }
243    }
244
245    pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self {
246        let val = env
247            .u256_val_from_be_bytes(bytes.to_object())
248            .unwrap_infallible();
249        U256 {
250            env: env.clone(),
251            val,
252        }
253    }
254
255    pub fn to_u128(&self) -> Option<u128> {
256        let v = *self.val.as_val();
257
258        // If v is U256Small it can be converted directly
259        if let Ok(small) = U256Small::try_from(v) {
260            return Some(u64::from(small) as u128);
261        }
262
263        // Otherwise use U256Object and take low sections if high are empty
264        let obj: U256Object = v.try_into().ok()?;
265        let hi_hi = self.env.obj_to_u256_hi_hi(obj).unwrap_infallible();
266        let hi_lo = self.env.obj_to_u256_hi_lo(obj).unwrap_infallible();
267        if hi_hi != 0 || hi_lo != 0 {
268            return None;
269        }
270        let lo_hi = self.env.obj_to_u256_lo_hi(obj).unwrap_infallible();
271        let lo_lo = self.env.obj_to_u256_lo_lo(obj).unwrap_infallible();
272        Some(((lo_hi as u128) << 64) | (lo_lo as u128))
273    }
274
275    pub fn to_be_bytes(&self) -> Bytes {
276        let obj = self
277            .env
278            .u256_val_to_be_bytes(self.to_val_type())
279            .unwrap_infallible();
280        unsafe { Bytes::unchecked_new(self.env.clone(), obj) }
281    }
282
283    pub fn add(&self, other: &U256) -> U256 {
284        let val = self.env.u256_add(self.val, other.val).unwrap_infallible();
285        U256 {
286            env: self.env.clone(),
287            val,
288        }
289    }
290
291    pub fn sub(&self, other: &U256) -> U256 {
292        let val = self.env.u256_sub(self.val, other.val).unwrap_infallible();
293        U256 {
294            env: self.env.clone(),
295            val,
296        }
297    }
298
299    pub fn mul(&self, other: &U256) -> U256 {
300        let val = self.env.u256_mul(self.val, other.val).unwrap_infallible();
301        U256 {
302            env: self.env.clone(),
303            val,
304        }
305    }
306
307    pub fn div(&self, other: &U256) -> U256 {
308        let val = self.env.u256_div(self.val, other.val).unwrap_infallible();
309        U256 {
310            env: self.env.clone(),
311            val,
312        }
313    }
314
315    pub fn rem_euclid(&self, other: &U256) -> U256 {
316        let val = self
317            .env
318            .u256_rem_euclid(self.val, other.val)
319            .unwrap_infallible();
320        U256 {
321            env: self.env.clone(),
322            val,
323        }
324    }
325
326    pub fn pow(&self, pow: u32) -> U256 {
327        let val = self.env.u256_pow(self.val, pow.into()).unwrap_infallible();
328        U256 {
329            env: self.env.clone(),
330            val,
331        }
332    }
333
334    pub fn shl(&self, bits: u32) -> U256 {
335        let val = self.env.u256_shl(self.val, bits.into()).unwrap_infallible();
336        U256 {
337            env: self.env.clone(),
338            val,
339        }
340    }
341
342    pub fn shr(&self, bits: u32) -> U256 {
343        let val = self.env.u256_shr(self.val, bits.into()).unwrap_infallible();
344        U256 {
345            env: self.env.clone(),
346            val,
347        }
348    }
349
350    /// Performs checked addition. Returns `None` if overflow occurred.
351    pub fn checked_add(&self, other: &U256) -> Option<U256> {
352        let val = self
353            .env
354            .u256_checked_add(self.val, other.val)
355            .unwrap_infallible();
356        if val.is_void() {
357            None
358        } else {
359            Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) })
360        }
361    }
362
363    /// Performs checked subtraction. Returns `None` if overflow occurred.
364    pub fn checked_sub(&self, other: &U256) -> Option<U256> {
365        let val = self
366            .env
367            .u256_checked_sub(self.val, other.val)
368            .unwrap_infallible();
369        if val.is_void() {
370            None
371        } else {
372            Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) })
373        }
374    }
375
376    /// Performs checked multiplication. Returns `None` if overflow occurred.
377    pub fn checked_mul(&self, other: &U256) -> Option<U256> {
378        let val = self
379            .env
380            .u256_checked_mul(self.val, other.val)
381            .unwrap_infallible();
382        if val.is_void() {
383            None
384        } else {
385            Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) })
386        }
387    }
388
389    /// Performs checked exponentiation. Returns `None` if overflow occurred.
390    pub fn checked_pow(&self, pow: u32) -> Option<U256> {
391        let val = self
392            .env
393            .u256_checked_pow(self.val, pow.into())
394            .unwrap_infallible();
395        if val.is_void() {
396            None
397        } else {
398            Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) })
399        }
400    }
401
402    /// Performs checked division. Returns `None` if `other` is zero.
403    pub fn checked_div(&self, other: &U256) -> Option<U256> {
404        if other.is_zero() {
405            return None;
406        }
407        Some(self.div(other))
408    }
409
410    /// Performs checked Euclidean remainder. Returns `None` if `other` is zero.
411    pub fn checked_rem_euclid(&self, other: &U256) -> Option<U256> {
412        if other.is_zero() {
413            return None;
414        }
415        Some(self.rem_euclid(other))
416    }
417
418    /// Performs checked left shift. Returns `None` if `bits >= 256`.
419    pub fn checked_shl(&self, bits: u32) -> Option<U256> {
420        if bits >= Self::BITS {
421            return None;
422        }
423        Some(self.shl(bits))
424    }
425
426    /// Performs checked right shift. Returns `None` if `bits >= 256`.
427    pub fn checked_shr(&self, bits: u32) -> Option<U256> {
428        if bits >= Self::BITS {
429            return None;
430        }
431        Some(self.shr(bits))
432    }
433}
434
435/// I256 holds a 256-bit signed integer.
436///
437/// ### Examples
438///
439/// ```
440/// use soroban_sdk::{I256, Env};
441///
442/// let env = Env::default();
443///
444/// let i1 = I256::from_i32(&env, -6);
445/// let i2 = I256::from_i32(&env, 3);
446/// assert_eq!(i1.add(&i2), I256::from_i32(&env, -3));
447/// ```
448#[derive(Clone)]
449pub struct I256 {
450    env: Env,
451    val: I256Val,
452}
453
454impl_num_wrapping_val_type!(I256, I256Val, I256Small);
455
456impl I256 {
457    pub const BITS: u32 = 256;
458
459    /// Returns the smallest value that can be represented by this type (-2^255).
460    pub fn min_value(env: &Env) -> Self {
461        Self::from_parts(env, i64::MIN, 0, 0, 0)
462    }
463
464    /// Returns the largest value that can be represented by this type (2^255 - 1).
465    pub fn max_value(env: &Env) -> Self {
466        Self::from_parts(env, i64::MAX, u64::MAX, u64::MAX, u64::MAX)
467    }
468
469    fn is_zero(&self) -> bool {
470        *self == I256::from_i32(&self.env, 0)
471    }
472
473    fn is_neg_one(&self) -> bool {
474        *self == I256::from_i32(&self.env, -1)
475    }
476
477    pub fn from_i32(env: &Env, i: i32) -> Self {
478        I256 {
479            env: env.clone(),
480            val: I256Val::from_i32(i),
481        }
482    }
483
484    pub fn from_i128(env: &Env, i: i128) -> Self {
485        let lo_hi = (i >> 64) as u64;
486        let lo_lo = i as u64;
487        let (hi_hi, hi_lo) = if i < 0 {
488            (-1_i64, u64::MAX) // sign extend 1 bit
489        } else {
490            (0_i64, 0_u64) // sign extend 0 bit
491        };
492        I256::from_parts(env, hi_hi, hi_lo, lo_hi, lo_lo)
493    }
494
495    pub fn from_parts(env: &Env, hi_hi: i64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self {
496        let obj = env
497            .obj_from_i256_pieces(hi_hi, hi_lo, lo_hi, lo_lo)
498            .unwrap_infallible();
499        I256 {
500            env: env.clone(),
501            val: obj.into(),
502        }
503    }
504
505    pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self {
506        let val = env
507            .i256_val_from_be_bytes(bytes.to_object())
508            .unwrap_infallible();
509        I256 {
510            env: env.clone(),
511            val,
512        }
513    }
514
515    pub fn to_i128(&self) -> Option<i128> {
516        let v = *self.val.as_val();
517
518        // If v is I256Small it can be converted directly
519        if let Ok(small) = I256Small::try_from(v) {
520            return Some(i64::from(small) as i128);
521        }
522
523        // Otherwise use I256Object and take low sections if high are either
524        // all 1 bits or all 0 bits (negative and positive respectively)
525        let obj: I256Object = v.try_into().ok()?;
526        let hi_hi = self.env.obj_to_i256_hi_hi(obj).unwrap_infallible();
527        let hi_lo = self.env.obj_to_i256_hi_lo(obj).unwrap_infallible();
528        let lo_hi = self.env.obj_to_i256_lo_hi(obj).unwrap_infallible();
529        let lo_lo = self.env.obj_to_i256_lo_lo(obj).unwrap_infallible();
530        // The low 128 bits as an i128
531        let lo = (((lo_hi as u128) << 64) | (lo_lo as u128)) as i128;
532
533        if lo < 0 && hi_hi == -1 && hi_lo == u64::MAX {
534            Some(lo) // if negative low, then high must be all 1 bit
535        } else if 0 <= lo && hi_hi == 0 && hi_lo == 0 {
536            Some(lo) // if non-negative low, then high must be all 0 bit
537        } else {
538            None
539        }
540    }
541
542    pub fn to_be_bytes(&self) -> Bytes {
543        let obj = self
544            .env
545            .i256_val_to_be_bytes(self.to_val_type())
546            .unwrap_infallible();
547        unsafe { Bytes::unchecked_new(self.env.clone(), obj) }
548    }
549
550    pub fn add(&self, other: &I256) -> I256 {
551        let val = self.env.i256_add(self.val, other.val).unwrap_infallible();
552        I256 {
553            env: self.env.clone(),
554            val,
555        }
556    }
557
558    pub fn sub(&self, other: &I256) -> I256 {
559        let val = self.env.i256_sub(self.val, other.val).unwrap_infallible();
560        I256 {
561            env: self.env.clone(),
562            val,
563        }
564    }
565
566    pub fn mul(&self, other: &I256) -> I256 {
567        let val = self.env.i256_mul(self.val, other.val).unwrap_infallible();
568        I256 {
569            env: self.env.clone(),
570            val,
571        }
572    }
573
574    pub fn div(&self, other: &I256) -> I256 {
575        let val = self.env.i256_div(self.val, other.val).unwrap_infallible();
576        I256 {
577            env: self.env.clone(),
578            val,
579        }
580    }
581
582    pub fn rem_euclid(&self, other: &I256) -> I256 {
583        let val = self
584            .env
585            .i256_rem_euclid(self.val, other.val)
586            .unwrap_infallible();
587        I256 {
588            env: self.env.clone(),
589            val,
590        }
591    }
592
593    pub fn pow(&self, pow: u32) -> I256 {
594        let val = self.env.i256_pow(self.val, pow.into()).unwrap_infallible();
595        I256 {
596            env: self.env.clone(),
597            val,
598        }
599    }
600
601    pub fn shl(&self, bits: u32) -> I256 {
602        let val = self.env.i256_shl(self.val, bits.into()).unwrap_infallible();
603        I256 {
604            env: self.env.clone(),
605            val,
606        }
607    }
608
609    pub fn shr(&self, bits: u32) -> I256 {
610        let val = self.env.i256_shr(self.val, bits.into()).unwrap_infallible();
611        I256 {
612            env: self.env.clone(),
613            val,
614        }
615    }
616
617    /// Performs checked addition. Returns `None` if overflow occurred.
618    pub fn checked_add(&self, other: &I256) -> Option<I256> {
619        let val = self
620            .env
621            .i256_checked_add(self.val, other.val)
622            .unwrap_infallible();
623        if val.is_void() {
624            None
625        } else {
626            Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) })
627        }
628    }
629
630    /// Performs checked subtraction. Returns `None` if overflow occurred.
631    pub fn checked_sub(&self, other: &I256) -> Option<I256> {
632        let val = self
633            .env
634            .i256_checked_sub(self.val, other.val)
635            .unwrap_infallible();
636        if val.is_void() {
637            None
638        } else {
639            Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) })
640        }
641    }
642
643    /// Performs checked multiplication. Returns `None` if overflow occurred.
644    pub fn checked_mul(&self, other: &I256) -> Option<I256> {
645        let val = self
646            .env
647            .i256_checked_mul(self.val, other.val)
648            .unwrap_infallible();
649        if val.is_void() {
650            None
651        } else {
652            Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) })
653        }
654    }
655
656    /// Performs checked exponentiation. Returns `None` if overflow occurred.
657    pub fn checked_pow(&self, pow: u32) -> Option<I256> {
658        let val = self
659            .env
660            .i256_checked_pow(self.val, pow.into())
661            .unwrap_infallible();
662        if val.is_void() {
663            None
664        } else {
665            Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) })
666        }
667    }
668
669    /// Returns `true` if dividing `self` by `other` would overflow or divide by zero.
670    /// This covers: `other == 0`, or `self == I256::MIN && other == -1`.
671    fn is_div_overflow(&self, other: &I256) -> bool {
672        if other.is_zero() {
673            return true;
674        }
675        if other.is_neg_one() {
676            let min = I256::min_value(&self.env);
677            if *self == min {
678                return true;
679            }
680        }
681        false
682    }
683
684    /// Performs checked division. Returns `None` if `other` is zero, or if
685    /// `self` is `I256::MIN` and `other` is `-1` (overflow).
686    pub fn checked_div(&self, other: &I256) -> Option<I256> {
687        if self.is_div_overflow(other) {
688            return None;
689        }
690        Some(self.div(other))
691    }
692
693    /// Performs checked Euclidean remainder. Returns `None` if `other` is zero,
694    /// or if `self` is `I256::MIN` and `other` is `-1` (overflow in intermediate
695    /// division).
696    pub fn checked_rem_euclid(&self, other: &I256) -> Option<I256> {
697        if self.is_div_overflow(other) {
698            return None;
699        }
700        Some(self.rem_euclid(other))
701    }
702
703    /// Performs checked left shift. Returns `None` if `bits >= 256`.
704    pub fn checked_shl(&self, bits: u32) -> Option<I256> {
705        if bits >= Self::BITS {
706            return None;
707        }
708        Some(self.shl(bits))
709    }
710
711    /// Performs checked right shift. Returns `None` if `bits >= 256`.
712    pub fn checked_shr(&self, bits: u32) -> Option<I256> {
713        if bits >= Self::BITS {
714            return None;
715        }
716        Some(self.shr(bits))
717    }
718}
719
720#[doc = "Timepoint holds a 64-bit unsigned integer."]
721#[derive(Clone)]
722pub struct Timepoint {
723    env: Env,
724    val: TimepointVal,
725}
726
727impl_num_wrapping_val_type!(Timepoint, TimepointVal, TimepointSmall);
728
729impl Timepoint {
730    /// Create a Timepoint from a unix time in seconds, the time in seconds
731    /// since January 1, 1970 UTC.
732    pub fn from_unix(env: &Env, seconds: u64) -> Timepoint {
733        let val = TimepointVal::try_from_val(env, &seconds).unwrap_optimized();
734        Timepoint {
735            env: env.clone(),
736            val,
737        }
738    }
739
740    /// Returns the Timepoint as unix time in seconds, the time in seconds since
741    /// January 1, 1970 UTC.
742    pub fn to_unix(&self) -> u64 {
743        u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized()
744    }
745}
746
747#[doc = "Duration holds a 64-bit unsigned integer."]
748#[derive(Clone)]
749pub struct Duration {
750    env: Env,
751    val: DurationVal,
752}
753
754impl_num_wrapping_val_type!(Duration, DurationVal, DurationSmall);
755
756impl Duration {
757    /// Create a Duration from seconds.
758    pub fn from_seconds(env: &Env, seconds: u64) -> Duration {
759        let val = DurationVal::try_from_val(env, &seconds).unwrap_optimized();
760        Duration {
761            env: env.clone(),
762            val,
763        }
764    }
765
766    /// Returns the Duration as seconds.
767    pub fn to_seconds(&self) -> u64 {
768        u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized()
769    }
770}
771
772#[cfg(test)]
773mod test {
774    use super::*;
775
776    #[test]
777    fn test_u256_roundtrip() {
778        let env = Env::default();
779
780        let u1 = U256::from_u32(&env, 12345);
781        let bytes = u1.to_be_bytes();
782        let u2 = U256::from_be_bytes(&env, &bytes);
783        assert_eq!(u1, u2);
784    }
785
786    #[test]
787    fn test_u256_u128_conversion() {
788        let env = Env::default();
789
790        // positive
791        let start = u128::MAX / 7;
792        let from = U256::from_u128(&env, start);
793        let end = from.to_u128().unwrap();
794        assert_eq!(start, end);
795
796        let over_u128 = from.mul(&U256::from_u32(&env, 8));
797        let failure = over_u128.to_u128();
798        assert_eq!(failure, None);
799
800        // zero
801        let start = 0_u128;
802        let from = U256::from_u128(&env, start);
803        let end = from.to_u128().unwrap();
804        assert_eq!(start, end);
805
806        // small (exercises the U256Small fast-path in to_u128)
807        let from_small = U256::from_u32(&env, 0);
808        assert_eq!(from_small.to_u128(), Some(0_u128));
809
810        let from_small = U256::from_u32(&env, u32::MAX);
811        assert_eq!(from_small.to_u128(), Some(u32::MAX as u128));
812    }
813
814    #[test]
815    fn test_i256_roundtrip() {
816        let env = Env::default();
817
818        let i1 = I256::from_i32(&env, -12345);
819        let bytes = i1.to_be_bytes();
820        let i2 = I256::from_be_bytes(&env, &bytes);
821        assert_eq!(i1, i2);
822    }
823
824    #[test]
825    fn test_i256_i128_conversion() {
826        let env = Env::default();
827
828        // positive
829        let start = i128::MAX / 7;
830        let from = I256::from_i128(&env, start);
831        let end = from.to_i128().unwrap();
832        assert_eq!(start, end);
833
834        let over_i128 = from.mul(&I256::from_i32(&env, 8));
835        let failure = over_i128.to_i128();
836        assert_eq!(failure, None);
837
838        // negative
839        let start = i128::MIN / 7;
840        let from = I256::from_i128(&env, start);
841        let end = from.to_i128().unwrap();
842        assert_eq!(start, end);
843
844        let over_i128 = from.mul(&I256::from_i32(&env, 8));
845        let failure = over_i128.to_i128();
846        assert_eq!(failure, None);
847
848        // zero
849        let start = 0_i128;
850        let from = I256::from_i128(&env, start);
851        let end = from.to_i128().unwrap();
852        assert_eq!(start, end);
853
854        // small (exercises the I256Small fast-path in to_i128)
855        let from_small = I256::from_i32(&env, 0);
856        assert_eq!(from_small.to_i128(), Some(0_i128));
857
858        let from_small = I256::from_i32(&env, i32::MAX);
859        assert_eq!(from_small.to_i128(), Some(i32::MAX as i128));
860
861        let from_small = I256::from_i32(&env, i32::MIN);
862        assert_eq!(from_small.to_i128(), Some(i32::MIN as i128));
863    }
864
865    #[test]
866    fn test_timepoint_roundtrip() {
867        let env = Env::default();
868
869        let tp = Timepoint::from_unix(&env, 123);
870        let u = tp.to_unix();
871        assert_eq!(u, 123);
872    }
873
874    #[test]
875    fn test_duration_roundtrip() {
876        let env = Env::default();
877
878        let tp = Duration::from_seconds(&env, 123);
879        let u = tp.to_seconds();
880        assert_eq!(u, 123);
881    }
882
883    #[test]
884    fn test_u256_arith() {
885        let env = Env::default();
886
887        let u1 = U256::from_u32(&env, 6);
888        let u2 = U256::from_u32(&env, 3);
889        assert_eq!(u1.add(&u2), U256::from_u32(&env, 9));
890        assert_eq!(u1.sub(&u2), U256::from_u32(&env, 3));
891        assert_eq!(u1.mul(&u2), U256::from_u32(&env, 18));
892        assert_eq!(u1.div(&u2), U256::from_u32(&env, 2));
893        assert_eq!(u1.pow(2), U256::from_u32(&env, 36));
894        assert_eq!(u1.shl(2), U256::from_u32(&env, 24));
895        assert_eq!(u1.shr(1), U256::from_u32(&env, 3));
896
897        let u3 = U256::from_u32(&env, 7);
898        let u4 = U256::from_u32(&env, 4);
899        assert_eq!(u3.rem_euclid(&u4), U256::from_u32(&env, 3));
900    }
901
902    #[test]
903    fn test_u256_min() {
904        let env = Env::default();
905
906        let min = U256::min_value(&env);
907        assert_eq!(min, U256::from_u32(&env, 0));
908
909        let one = U256::from_u32(&env, 1);
910        assert_eq!(min.checked_sub(&one), None);
911        assert!(min.checked_add(&one).is_some());
912    }
913
914    #[test]
915    fn test_u256_max() {
916        let env = Env::default();
917
918        let max = U256::max_value(&env);
919        assert_eq!(
920            max,
921            U256::from_parts(&env, u64::MAX, u64::MAX, u64::MAX, u64::MAX)
922        );
923
924        let u128_max = U256::from_u128(&env, u128::MAX);
925        assert!(max > u128_max);
926
927        let one = U256::from_u32(&env, 1);
928        assert_eq!(max.checked_add(&one), None);
929        assert!(max.checked_sub(&one).is_some());
930    }
931
932    #[test]
933    fn test_u256_checked_arith() {
934        let env = Env::default();
935
936        let u1 = U256::from_u32(&env, 6);
937        let u2 = U256::from_u32(&env, 3);
938        assert_eq!(u1.checked_add(&u2), Some(U256::from_u32(&env, 9)));
939        assert_eq!(u1.checked_sub(&u2), Some(U256::from_u32(&env, 3)));
940        assert_eq!(u1.checked_mul(&u2), Some(U256::from_u32(&env, 18)));
941        assert_eq!(u1.checked_div(&u2), Some(U256::from_u32(&env, 2)));
942        assert_eq!(u1.checked_pow(2), Some(U256::from_u32(&env, 36)));
943        assert_eq!(u1.checked_shl(2), Some(U256::from_u32(&env, 24)));
944        assert_eq!(u1.checked_shr(1), Some(U256::from_u32(&env, 3)));
945
946        let u3 = U256::from_u32(&env, 7);
947        let u4 = U256::from_u32(&env, 4);
948        assert_eq!(u3.checked_rem_euclid(&u4), Some(U256::from_u32(&env, 3)));
949    }
950
951    #[test]
952    fn test_u256_checked_arith_overflow() {
953        let env = Env::default();
954
955        let zero = U256::from_u32(&env, 0);
956        let one = U256::from_u32(&env, 1);
957        let two = U256::from_u32(&env, 2);
958        let max = U256::max_value(&env);
959        assert_eq!(max.checked_add(&one), None);
960        assert_eq!(zero.checked_sub(&one), None);
961        assert_eq!(max.checked_mul(&two), None);
962        assert_eq!(one.checked_div(&zero), None);
963        assert_eq!(max.checked_pow(2), None);
964        assert_eq!(one.checked_shl(256), None);
965        assert_eq!(one.checked_shr(256), None);
966        assert_eq!(one.checked_rem_euclid(&zero), None);
967
968        let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0);
969        let one_from_parts = U256::from_parts(&env, 0, 0, 0, 1);
970        assert_eq!(one.checked_div(&zero_from_parts), None);
971        assert_eq!(zero.checked_sub(&one_from_parts), None);
972    }
973
974    #[test]
975    fn test_u256_is_zero() {
976        let env = Env::default();
977
978        let zero = U256::from_u32(&env, 0);
979        let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0);
980        let non_zero = U256::from_u32(&env, 1);
981
982        assert!(zero.is_zero());
983        assert!(zero_from_parts.is_zero());
984        assert!(!non_zero.is_zero());
985    }
986
987    #[test]
988    fn test_i256_arith() {
989        let env = Env::default();
990
991        let i1 = I256::from_i32(&env, -6);
992        let i2 = I256::from_i32(&env, 3);
993        assert_eq!(i1.add(&i2), I256::from_i32(&env, -3));
994        assert_eq!(i1.sub(&i2), I256::from_i32(&env, -9));
995        assert_eq!(i1.mul(&i2), I256::from_i32(&env, -18));
996        assert_eq!(i1.div(&i2), I256::from_i32(&env, -2));
997        assert_eq!(i1.pow(2), I256::from_i32(&env, 36));
998        assert_eq!(i1.shl(2), I256::from_i32(&env, -24));
999        assert_eq!(i1.shr(1), I256::from_i32(&env, -3));
1000
1001        let u3 = I256::from_i32(&env, -7);
1002        let u4 = I256::from_i32(&env, 4);
1003        assert_eq!(u3.rem_euclid(&u4), I256::from_i32(&env, 1));
1004    }
1005
1006    #[test]
1007    fn test_i256_min() {
1008        let env = Env::default();
1009
1010        let min = I256::min_value(&env);
1011        assert_eq!(min, I256::from_parts(&env, i64::MIN, 0, 0, 0));
1012
1013        let i128_min = I256::from_i128(&env, i128::MIN);
1014        assert!(min < i128_min);
1015
1016        let one = I256::from_i32(&env, 1);
1017        assert_eq!(min.checked_sub(&one), None);
1018        assert!(min.checked_add(&one).is_some());
1019    }
1020
1021    #[test]
1022    fn test_i256_max() {
1023        let env = Env::default();
1024
1025        let max = I256::max_value(&env);
1026        assert_eq!(
1027            max,
1028            I256::from_parts(&env, i64::MAX, u64::MAX, u64::MAX, u64::MAX)
1029        );
1030
1031        let i128_max = I256::from_i128(&env, i128::MAX);
1032        assert!(max > i128_max);
1033
1034        let one = I256::from_i32(&env, 1);
1035        assert_eq!(max.checked_add(&one), None);
1036        assert!(max.checked_sub(&one).is_some());
1037    }
1038
1039    #[test]
1040    fn test_i256_checked_arith() {
1041        let env = Env::default();
1042
1043        let i1 = I256::from_i32(&env, -6);
1044        let i2 = I256::from_i32(&env, 3);
1045        assert_eq!(i1.checked_add(&i2), Some(I256::from_i32(&env, -3)));
1046        assert_eq!(i1.checked_sub(&i2), Some(I256::from_i32(&env, -9)));
1047        assert_eq!(i1.checked_mul(&i2), Some(I256::from_i32(&env, -18)));
1048        assert_eq!(i1.checked_div(&i2), Some(I256::from_i32(&env, -2)));
1049        assert_eq!(i1.checked_pow(2), Some(I256::from_i32(&env, 36)));
1050        assert_eq!(i1.checked_shl(2), Some(I256::from_i32(&env, -24)));
1051        assert_eq!(i1.checked_shr(1), Some(I256::from_i32(&env, -3)));
1052
1053        let u3 = I256::from_i32(&env, -7);
1054        let u4 = I256::from_i32(&env, 4);
1055        assert_eq!(u3.checked_rem_euclid(&u4), Some(I256::from_i32(&env, 1)));
1056    }
1057
1058    #[test]
1059    fn test_i256_checked_arith_overflow() {
1060        let env = Env::default();
1061
1062        let zero = I256::from_i32(&env, 0);
1063        let one = I256::from_i32(&env, 1);
1064        let negative_one = I256::from_i32(&env, -1);
1065        let two = I256::from_i32(&env, 2);
1066        let max = I256::max_value(&env);
1067        let min = I256::min_value(&env);
1068        assert_eq!(max.checked_add(&one), None);
1069        assert_eq!(min.checked_sub(&one), None);
1070        assert_eq!(max.checked_mul(&two), None);
1071        assert_eq!(one.checked_div(&zero), None);
1072        assert_eq!(min.checked_div(&negative_one), None);
1073        assert_eq!(max.checked_pow(2), None);
1074        assert_eq!(one.checked_shl(256), None);
1075        assert_eq!(one.checked_shr(256), None);
1076        assert_eq!(one.checked_rem_euclid(&zero), None);
1077
1078        let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0);
1079        let one_from_parts = I256::from_parts(&env, 0, 0, 0, 1);
1080        assert_eq!(one.checked_div(&zero_from_parts), None);
1081        assert_eq!(min.checked_sub(&one_from_parts), None);
1082    }
1083
1084    #[test]
1085    fn test_i256_is_zero() {
1086        let env = Env::default();
1087
1088        let zero = I256::from_i32(&env, 0);
1089        let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0);
1090        let non_zero = I256::from_i32(&env, 1);
1091
1092        assert!(zero.is_zero());
1093        assert!(zero_from_parts.is_zero());
1094        assert!(!non_zero.is_zero());
1095    }
1096
1097    #[test]
1098    fn test_i256_is_neg_one() {
1099        let env = Env::default();
1100
1101        let negative_one = I256::from_i32(&env, -1);
1102        let negative_one_from_parts = I256::from_parts(&env, -1, u64::MAX, u64::MAX, u64::MAX);
1103        let negative_two = I256::from_i32(&env, -2);
1104
1105        assert!(negative_one.is_neg_one());
1106        assert!(negative_one_from_parts.is_neg_one());
1107        assert!(!negative_two.is_neg_one());
1108    }
1109
1110    #[test]
1111    fn test_i256_is_div_overflow() {
1112        let env = Env::default();
1113
1114        let zero = I256::from_i32(&env, 0);
1115        let negative_one = I256::from_i32(&env, -1);
1116        let min = I256::min_value(&env);
1117
1118        assert!(!zero.is_div_overflow(&negative_one));
1119
1120        assert!(negative_one.is_div_overflow(&zero));
1121        assert!(min.is_div_overflow(&negative_one));
1122    }
1123}