1use core::cmp::Ordering;
2
3use crate::xdr::{Int256Parts, ScVal, UInt256Parts};
4use crate::{
5 declare_tag_based_signed_small_and_object_wrappers,
6 declare_tag_based_small_and_object_wrappers,
7 declare_tag_based_unsigned_small_and_object_wrappers, declare_tag_based_wrapper, val::TAG_BITS,
8 Compare, ConversionError, Env, Tag, Val,
9};
10pub use ethnum::{AsI256, AsU256, I256, U256};
11
12declare_tag_based_wrapper!(U32Val);
13declare_tag_based_wrapper!(I32Val);
14
15impl Val {
16 #[inline(always)]
17 pub const fn from_u32(u: u32) -> U32Val {
18 unsafe { U32Val(Val::from_major_minor_and_tag(u, 0, Tag::U32Val)) }
19 }
20
21 #[inline(always)]
22 pub const fn from_i32(i: i32) -> I32Val {
23 unsafe { I32Val(Val::from_major_minor_and_tag(i as u32, 0, Tag::I32Val)) }
24 }
25}
26
27impl<E: Env> Compare<U32Val> for E {
28 type Error = E::Error;
29 fn compare(&self, a: &U32Val, b: &U32Val) -> Result<Ordering, Self::Error> {
30 Ok(u32::from(*a).cmp(&u32::from(*b)))
31 }
32}
33
34impl<E: Env> Compare<I32Val> for E {
35 type Error = E::Error;
36 fn compare(&self, a: &I32Val, b: &I32Val) -> Result<Ordering, Self::Error> {
37 Ok(i32::from(*a).cmp(&i32::from(*b)))
38 }
39}
40
41declare_tag_based_unsigned_small_and_object_wrappers!(U64Val, U64Small, U64Object);
42declare_tag_based_signed_small_and_object_wrappers!(I64Val, I64Small, I64Object);
43declare_tag_based_unsigned_small_and_object_wrappers!(
44 TimepointVal,
45 TimepointSmall,
46 TimepointObject
47);
48declare_tag_based_unsigned_small_and_object_wrappers!(DurationVal, DurationSmall, DurationObject);
49
50declare_tag_based_unsigned_small_and_object_wrappers!(U128Val, U128Small, U128Object);
51declare_tag_based_signed_small_and_object_wrappers!(I128Val, I128Small, I128Object);
52declare_tag_based_unsigned_small_and_object_wrappers!(U256Val, U256Small, U256Object);
53declare_tag_based_signed_small_and_object_wrappers!(I256Val, I256Small, I256Object);
54
55impl From<u32> for U32Val {
56 fn from(value: u32) -> Self {
57 U32Val(value.into())
58 }
59}
60
61impl From<U32Val> for u32 {
62 fn from(value: U32Val) -> Self {
63 value.0.get_major()
64 }
65}
66
67impl From<i32> for I32Val {
68 fn from(value: i32) -> Self {
69 I32Val(value.into())
70 }
71}
72
73impl From<I32Val> for i32 {
74 fn from(value: I32Val) -> Self {
75 value.0.get_major() as i32
76 }
77}
78
79impl From<U64Small> for u64 {
80 fn from(value: U64Small) -> Self {
81 value.0.get_body()
82 }
83}
84
85impl From<I64Small> for i64 {
86 fn from(value: I64Small) -> Self {
87 value.0.get_signed_body()
88 }
89}
90
91impl From<TimepointSmall> for u64 {
92 fn from(value: TimepointSmall) -> Self {
93 value.0.get_body()
94 }
95}
96
97impl From<DurationSmall> for u64 {
98 fn from(value: DurationSmall) -> Self {
99 value.0.get_body()
100 }
101}
102
103impl From<U128Small> for u128 {
104 fn from(value: U128Small) -> Self {
105 value.0.get_body() as u128
106 }
107}
108
109impl From<I128Small> for i128 {
110 fn from(value: I128Small) -> Self {
111 value.0.get_signed_body() as i128
112 }
113}
114
115impl From<U256Small> for U256 {
116 fn from(value: U256Small) -> Self {
117 U256::from(value.0.get_body())
118 }
119}
120
121impl From<I256Small> for I256 {
122 fn from(value: I256Small) -> Self {
123 I256::from(value.0.get_signed_body())
124 }
125}
126
127impl TryFrom<u64> for U64Small {
128 type Error = ConversionError;
129 fn try_from(value: u64) -> Result<Self, Self::Error> {
130 if is_small_u64(value) {
131 Ok(Self(unsafe {
132 Val::from_body_and_tag(value, Tag::U64Small)
133 }))
134 } else {
135 Err(ConversionError)
136 }
137 }
138}
139
140impl TryFrom<i64> for I64Small {
141 type Error = ConversionError;
142 fn try_from(value: i64) -> Result<Self, Self::Error> {
143 if is_small_i64(value) {
144 Ok(Self(unsafe {
145 Val::from_body_and_tag(value as u64, Tag::I64Small)
146 }))
147 } else {
148 Err(ConversionError)
149 }
150 }
151}
152
153impl TryFrom<u64> for TimepointSmall {
154 type Error = ConversionError;
155 fn try_from(value: u64) -> Result<Self, Self::Error> {
156 if is_small_u64(value) {
157 Ok(Self(unsafe {
158 Val::from_body_and_tag(value, Tag::TimepointSmall)
159 }))
160 } else {
161 Err(ConversionError)
162 }
163 }
164}
165
166impl TryFrom<u64> for DurationSmall {
167 type Error = ConversionError;
168 fn try_from(value: u64) -> Result<Self, Self::Error> {
169 if is_small_u64(value) {
170 Ok(Self(unsafe {
171 Val::from_body_and_tag(value, Tag::DurationSmall)
172 }))
173 } else {
174 Err(ConversionError)
175 }
176 }
177}
178
179impl TryFrom<TimepointSmall> for ScVal {
180 type Error = ConversionError;
181 fn try_from(value: TimepointSmall) -> Result<Self, ConversionError> {
182 Ok(ScVal::Timepoint(value.as_val().get_body().into()))
183 }
184}
185
186impl TryFrom<&TimepointSmall> for ScVal {
187 type Error = ConversionError;
188 fn try_from(value: &TimepointSmall) -> Result<Self, ConversionError> {
189 (*value).try_into()
190 }
191}
192
193impl TryFrom<DurationSmall> for ScVal {
194 type Error = ConversionError;
195 fn try_from(value: DurationSmall) -> Result<Self, ConversionError> {
196 Ok(ScVal::Duration(value.as_val().get_body().into()))
197 }
198}
199
200impl TryFrom<&DurationSmall> for ScVal {
201 type Error = ConversionError;
202 fn try_from(value: &DurationSmall) -> Result<Self, ConversionError> {
203 (*value).try_into()
204 }
205}
206
207impl TryFrom<u128> for U128Small {
208 type Error = ConversionError;
209 fn try_from(value: u128) -> Result<Self, Self::Error> {
210 if is_small_u128(value) {
211 Ok(Self(unsafe {
212 Val::from_body_and_tag(value as u64, Tag::U128Small)
213 }))
214 } else {
215 Err(ConversionError)
216 }
217 }
218}
219
220impl TryFrom<i128> for I128Small {
221 type Error = ConversionError;
222 fn try_from(value: i128) -> Result<Self, Self::Error> {
223 if is_small_i128(value) {
224 Ok(Self(unsafe {
225 Val::from_body_and_tag((value as u128) as u64, Tag::I128Small)
226 }))
227 } else {
228 Err(ConversionError)
229 }
230 }
231}
232
233impl From<U256Small> for u64 {
234 fn from(value: U256Small) -> Self {
235 value.0.get_body()
236 }
237}
238
239impl TryFrom<U256> for U256Small {
240 type Error = ConversionError;
241 fn try_from(value: U256) -> Result<Self, Self::Error> {
242 if is_small_u256(&value) {
243 Ok(Self(unsafe {
244 Val::from_body_and_tag(value.as_u64(), Tag::U256Small)
245 }))
246 } else {
247 Err(ConversionError)
248 }
249 }
250}
251
252impl From<I256Small> for i64 {
253 fn from(value: I256Small) -> Self {
254 value.0.get_signed_body()
255 }
256}
257
258impl TryFrom<I256> for I256Small {
259 type Error = ConversionError;
260 fn try_from(value: I256) -> Result<Self, Self::Error> {
261 if is_small_i256(&value) {
262 Ok(Self(unsafe {
263 Val::from_body_and_tag(value.as_i64() as u64, Tag::I256Small)
264 }))
265 } else {
266 Err(ConversionError)
267 }
268 }
269}
270
271impl TryFrom<U256Small> for ScVal {
272 type Error = ConversionError;
273 fn try_from(value: U256Small) -> Result<Self, ConversionError> {
274 let val = U256::new(value.as_val().get_body() as u128);
275 let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_into_pieces(val);
276 Ok(ScVal::U256(UInt256Parts {
277 hi_hi,
278 hi_lo,
279 lo_hi,
280 lo_lo,
281 }))
282 }
283}
284
285impl TryFrom<&U256Small> for ScVal {
286 type Error = ConversionError;
287 fn try_from(value: &U256Small) -> Result<Self, ConversionError> {
288 (*value).try_into()
289 }
290}
291
292impl TryFrom<I256Small> for ScVal {
293 type Error = ConversionError;
294 fn try_from(value: I256Small) -> Result<Self, ConversionError> {
295 let val = I256::new(value.as_val().get_signed_body() as i128);
296 let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(val);
297 Ok(ScVal::I256(Int256Parts {
298 hi_hi,
299 hi_lo,
300 lo_hi,
301 lo_lo,
302 }))
303 }
304}
305
306impl TryFrom<&I256Small> for ScVal {
307 type Error = ConversionError;
308 fn try_from(value: &I256Small) -> Result<Self, ConversionError> {
309 (*value).try_into()
310 }
311}
312
313impl I64Small {
317 pub const fn from_i32(small: i32) -> Self {
318 let extended = small as i64;
319 unsafe { I64Small::from_body(extended as u64) }
320 }
321}
322
323impl I64Val {
324 pub const fn from_i32(small: i32) -> Self {
325 Self::from_small(I64Small::from_i32(small))
326 }
327}
328
329impl U64Small {
330 pub const fn from_u32(small: u32) -> Self {
331 let extended = small as u64;
332 unsafe { U64Small::from_body(extended) }
333 }
334}
335
336impl U64Val {
337 pub const fn from_u32(small: u32) -> Self {
338 Self::from_small(U64Small::from_u32(small))
339 }
340}
341
342impl I128Small {
343 pub const fn from_i32(small: i32) -> Self {
344 let extended = small as i64;
345 unsafe { I128Small::from_body(extended as u64) }
346 }
347}
348
349impl I128Val {
350 pub const fn from_i32(small: i32) -> Self {
351 Self::from_small(I128Small::from_i32(small))
352 }
353}
354
355impl U128Small {
356 pub const fn from_u32(small: u32) -> Self {
357 let extended = small as u64;
358 unsafe { U128Small::from_body(extended) }
359 }
360}
361
362impl U128Val {
363 pub const fn from_u32(small: u32) -> Self {
364 Self::from_small(U128Small::from_u32(small))
365 }
366}
367
368impl I256Small {
369 pub const fn from_i32(small: i32) -> Self {
370 let extended = small as i64;
371 unsafe { I256Small::from_body(extended as u64) }
372 }
373}
374
375impl I256Val {
376 pub const fn from_i32(small: i32) -> Self {
377 Self::from_small(I256Small::from_i32(small))
378 }
379}
380
381impl U256Small {
382 pub const fn from_u32(small: u32) -> Self {
383 let extended = small as u64;
384 unsafe { U256Small::from_body(extended) }
385 }
386}
387
388impl U256Val {
389 pub const fn from_u32(small: u32) -> Self {
390 Self::from_small(U256Small::from_u32(small))
391 }
392}
393
394pub const fn is_small_u64(u: u64) -> bool {
395 u == ((u << TAG_BITS) >> TAG_BITS)
396}
397
398pub const fn is_small_i64(i: i64) -> bool {
399 i == ((i << TAG_BITS) >> TAG_BITS)
400}
401
402pub fn is_small_u128(u: u128) -> bool {
403 let word = u as u64;
404 is_small_u64(word) && u == (word as u128)
405}
406
407pub fn is_small_i128(i: i128) -> bool {
408 let word = i as i64;
409 is_small_i64(word) && i == (word as i128)
410}
411
412pub fn is_small_u256(u: &U256) -> bool {
413 let word = u.as_u64();
414 is_small_u64(word) && *u == U256::from(word)
415}
416
417pub fn is_small_i256(i: &I256) -> bool {
418 let word = i.as_i64();
419 is_small_i64(word) && *i == I256::from(word)
420}
421
422pub fn is_small_u256_parts(u: &UInt256Parts) -> bool {
423 u.hi_hi == 0 && u.hi_lo == 0 && u.lo_hi == 0 && is_small_u64(u.lo_lo)
424}
425
426pub fn is_small_i256_parts(i: &Int256Parts) -> bool {
427 let i = i256_from_pieces(i.hi_hi, i.hi_lo, i.lo_hi, i.lo_lo);
428 is_small_i256(&i)
429}
430
431pub fn u256_from_pieces(hi_hi: u64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> U256 {
432 let high = (u128::from(hi_hi)) << 64 | u128::from(hi_lo);
433 let low = (u128::from(lo_hi)) << 64 | u128::from(lo_lo);
434 U256::from_words(high, low)
435}
436
437pub fn u256_into_pieces(u: U256) -> (u64, u64, u64, u64) {
438 let (high, low) = u.into_words();
439 let (hi_hi, hi_lo) = ((high >> 64) as u64, high as u64);
440 let (lo_hi, lo_lo) = ((low >> 64) as u64, low as u64);
441 (hi_hi, hi_lo, lo_hi, lo_lo)
442}
443
444pub fn i256_from_pieces(hi_hi: i64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> I256 {
445 let high = ((u128::from(hi_hi as u64) << 64) | u128::from(hi_lo)) as i128;
446 let low = ((u128::from(lo_hi) << 64) | u128::from(lo_lo)) as i128;
447 I256::from_words(high, low)
448}
449
450pub fn i256_into_pieces(i: I256) -> (i64, u64, u64, u64) {
451 let (high, low) = i.into_words();
452 let (hi_hi, hi_lo) = ((high >> 64) as i64, high as u64);
453 let (lo_hi, lo_lo) = ((low >> 64) as u64, low as u64);
454 (hi_hi, hi_lo, lo_hi, lo_lo)
455}
456
457pub const MIN_SMALL_U64: u64 = 0;
458pub const MAX_SMALL_U64: u64 = 0x00ff_ffff_ffff_ffff_u64;
459
460pub const MIN_SMALL_I64: i64 = 0xff80_0000_0000_0000_u64 as i64;
461pub const MAX_SMALL_I64: i64 = 0x007f_ffff_ffff_ffff_u64 as i64;
462
463static_assertions::const_assert!(MIN_SMALL_I64 == -36_028_797_018_963_968_i64);
464static_assertions::const_assert!(MAX_SMALL_I64 == 36_028_797_018_963_967_i64);
465
466pub const MIN_SMALL_U128: u128 = MIN_SMALL_U64 as u128;
467pub const MAX_SMALL_U128: u128 = MAX_SMALL_U64 as u128;
468
469pub const MIN_SMALL_I128: i128 = MIN_SMALL_I64 as i128;
470pub const MAX_SMALL_I128: i128 = MAX_SMALL_I64 as i128;
471
472pub const MIN_SMALL_U256: U256 = U256::new(MIN_SMALL_U128);
473pub const MAX_SMALL_U256: U256 = U256::new(MAX_SMALL_U128);
474
475pub const MIN_SMALL_I256: I256 = I256::new(MIN_SMALL_I128);
476pub const MAX_SMALL_I256: I256 = I256::new(MAX_SMALL_I128);
477
478#[test]
479fn test_small_ints() {
480 assert!(!is_small_i64(MIN_SMALL_I64 - 1));
481 assert!(is_small_i64(MIN_SMALL_I64));
482 assert!(is_small_i64(MAX_SMALL_I64));
483 assert!(!is_small_i64(MAX_SMALL_I64 + 1));
484
485 assert!(is_small_u64(MIN_SMALL_U64));
486 assert!(is_small_u64(MAX_SMALL_U64));
487 assert!(!is_small_u64(MAX_SMALL_U64 + 1));
488
489 assert!(!is_small_i128(MIN_SMALL_I128 - 1));
490 assert!(is_small_i128(MIN_SMALL_I128));
491 assert!(is_small_i128(MAX_SMALL_I128));
492 assert!(!is_small_i128(MAX_SMALL_I128 + 1));
493
494 assert!(is_small_u128(MIN_SMALL_U128));
495 assert!(is_small_u128(MAX_SMALL_U128));
496 assert!(!is_small_u128(MAX_SMALL_U128 + 1));
497
498 assert!(!is_small_i256(&(MIN_SMALL_I256 - 1)));
499 assert!(is_small_i256(&(MIN_SMALL_I256)));
500 assert!(is_small_i256(&(MAX_SMALL_I256)));
501 assert!(!is_small_i256(&(MAX_SMALL_I256 + 1)));
502
503 assert!(is_small_u256(&(MIN_SMALL_U256)));
504 assert!(is_small_u256(&(MAX_SMALL_U256)));
505 assert!(!is_small_u256(&(MAX_SMALL_U256 + 1)));
506
507 assert!(is_small_i64(-1_i64));
508 assert!(is_small_i64(-12345_i64));
509 assert!(is_small_i64(1_i64));
510 assert!(is_small_i64(12345_i64));
511
512 assert!(is_small_i128(-1_i128));
513 assert!(is_small_i128(-12345_i128));
514 assert!(is_small_i128(1_i128));
515 assert!(is_small_i128(12345_i128));
516
517 assert!(is_small_i256(&I256::new(-1_i128)));
518 assert!(is_small_i256(&I256::new(-12345_i128)));
519 assert!(is_small_i256(&I256::new(1_i128)));
520 assert!(is_small_i256(&I256::new(12345_i128)));
521}