stellar_xdr/next/
scval_conversions.rs

1use super::{
2    Int128Parts, ScBytes, ScError, ScMap, ScMapEntry, ScSymbol, ScVal, ScVec, UInt128Parts,
3};
4
5#[cfg(all(not(feature = "std"), feature = "alloc"))]
6extern crate alloc;
7#[cfg(all(not(feature = "std"), feature = "alloc"))]
8use alloc::{string::String, vec, vec::Vec};
9
10// TODO: Use the Error type for conversions in this file.
11
12impl From<ScError> for ScVal {
13    fn from(v: ScError) -> Self {
14        ScVal::Error(v)
15    }
16}
17
18impl TryFrom<ScVal> for ScError {
19    type Error = ();
20    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
21        if let ScVal::Error(s) = v {
22            Ok(s)
23        } else {
24            Err(())
25        }
26    }
27}
28
29impl From<i32> for ScVal {
30    fn from(v: i32) -> ScVal {
31        ScVal::I32(v)
32    }
33}
34
35impl From<&i32> for ScVal {
36    fn from(v: &i32) -> ScVal {
37        ScVal::I32(*v)
38    }
39}
40
41impl TryFrom<ScVal> for i32 {
42    type Error = ();
43    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
44        if let ScVal::I32(i) = v {
45            Ok(i)
46        } else {
47            Err(())
48        }
49    }
50}
51
52impl From<u32> for ScVal {
53    fn from(v: u32) -> ScVal {
54        ScVal::U32(v)
55    }
56}
57
58impl From<&u32> for ScVal {
59    fn from(v: &u32) -> ScVal {
60        ScVal::U32(*v)
61    }
62}
63
64impl TryFrom<ScVal> for u32 {
65    type Error = ();
66    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
67        if let ScVal::U32(i) = v {
68            Ok(i)
69        } else {
70            Err(())
71        }
72    }
73}
74
75impl From<i64> for ScVal {
76    fn from(v: i64) -> ScVal {
77        ScVal::I64(v)
78    }
79}
80
81impl From<&i64> for ScVal {
82    fn from(v: &i64) -> ScVal {
83        <_ as Into<ScVal>>::into(*v)
84    }
85}
86
87impl TryFrom<ScVal> for i64 {
88    type Error = ();
89    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
90        if let ScVal::I64(i) = v {
91            Ok(i)
92        } else {
93            Err(())
94        }
95    }
96}
97
98impl From<()> for ScVal {
99    fn from((): ()) -> Self {
100        ScVal::Void
101    }
102}
103
104impl From<&()> for ScVal {
105    fn from((): &()) -> Self {
106        ScVal::Void
107    }
108}
109
110impl TryFrom<ScVal> for () {
111    type Error = ();
112    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
113        if let ScVal::Void = v {
114            Ok(())
115        } else {
116            Err(())
117        }
118    }
119}
120
121impl From<bool> for ScVal {
122    fn from(v: bool) -> Self {
123        ScVal::Bool(v)
124    }
125}
126
127impl From<&bool> for ScVal {
128    fn from(v: &bool) -> Self {
129        <_ as Into<ScVal>>::into(*v)
130    }
131}
132
133impl TryFrom<ScVal> for bool {
134    type Error = ();
135    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
136        if let ScVal::Bool(b) = v {
137            Ok(b)
138        } else {
139            Err(())
140        }
141    }
142}
143
144impl From<u64> for ScVal {
145    fn from(v: u64) -> Self {
146        ScVal::U64(v)
147    }
148}
149
150impl From<&u64> for ScVal {
151    fn from(v: &u64) -> Self {
152        ScVal::U64(*v)
153    }
154}
155
156impl TryFrom<ScVal> for u64 {
157    type Error = ();
158    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
159        if let ScVal::U64(i) = v {
160            Ok(i)
161        } else {
162            Err(())
163        }
164    }
165}
166
167pub mod int128_helpers {
168    #[must_use]
169    #[inline(always)]
170    #[allow(clippy::inline_always, clippy::cast_possible_truncation)]
171    pub fn u128_hi(u: u128) -> u64 {
172        (u >> 64) as u64
173    }
174
175    #[must_use]
176    #[inline(always)]
177    #[allow(clippy::inline_always, clippy::cast_possible_truncation)]
178    pub fn u128_lo(u: u128) -> u64 {
179        u as u64
180    }
181
182    #[must_use]
183    #[inline(always)]
184    #[allow(clippy::inline_always)]
185    pub fn u128_from_pieces(hi: u64, lo: u64) -> u128 {
186        (u128::from(hi) << 64) | u128::from(lo)
187    }
188
189    #[must_use]
190    #[inline(always)]
191    #[allow(clippy::inline_always, clippy::cast_possible_truncation)]
192    pub fn i128_hi(i: i128) -> i64 {
193        (i >> 64) as i64
194    }
195
196    #[must_use]
197    #[inline(always)]
198    #[allow(
199        clippy::inline_always,
200        clippy::cast_possible_truncation,
201        clippy::cast_sign_loss
202    )]
203    pub fn i128_lo(i: i128) -> u64 {
204        i as u64
205    }
206
207    #[must_use]
208    #[inline(always)]
209    #[allow(
210        clippy::inline_always,
211        clippy::cast_sign_loss,
212        clippy::cast_possible_wrap
213    )]
214    pub fn i128_from_pieces(hi: i64, lo: u64) -> i128 {
215        (u128::from(hi as u64) << 64 | u128::from(lo)) as i128
216    }
217}
218
219#[allow(clippy::wildcard_imports)]
220use int128_helpers::*;
221
222impl From<u128> for ScVal {
223    fn from(v: u128) -> Self {
224        ScVal::U128(UInt128Parts {
225            hi: u128_hi(v),
226            lo: u128_lo(v),
227        })
228    }
229}
230
231impl From<&u128> for ScVal {
232    fn from(v: &u128) -> Self {
233        <ScVal as From<u128>>::from(*v)
234    }
235}
236
237impl From<&UInt128Parts> for u128 {
238    fn from(v: &UInt128Parts) -> Self {
239        u128_from_pieces(v.hi, v.lo)
240    }
241}
242
243impl TryFrom<ScVal> for u128 {
244    type Error = ();
245    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
246        if let ScVal::U128(i) = v {
247            Ok((&i).into())
248        } else {
249            Err(())
250        }
251    }
252}
253
254impl From<i128> for ScVal {
255    fn from(v: i128) -> Self {
256        ScVal::I128(Int128Parts {
257            hi: i128_hi(v),
258            lo: i128_lo(v),
259        })
260    }
261}
262
263impl From<&i128> for ScVal {
264    fn from(v: &i128) -> Self {
265        <ScVal as From<i128>>::from(*v)
266    }
267}
268
269impl From<&Int128Parts> for i128 {
270    fn from(v: &Int128Parts) -> Self {
271        i128_from_pieces(v.hi, v.lo)
272    }
273}
274
275impl TryFrom<ScVal> for i128 {
276    type Error = ();
277    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
278        if let ScVal::I128(i) = v {
279            Ok((&i).into())
280        } else {
281            Err(())
282        }
283    }
284}
285
286impl From<ScSymbol> for ScVal {
287    fn from(v: ScSymbol) -> Self {
288        ScVal::Symbol(v)
289    }
290}
291
292impl TryFrom<ScVal> for ScSymbol {
293    type Error = ();
294    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
295        if let ScVal::Symbol(s) = v {
296            Ok(s)
297        } else {
298            Err(())
299        }
300    }
301}
302
303#[cfg(feature = "alloc")]
304impl TryFrom<String> for ScVal {
305    type Error = ();
306    fn try_from(v: String) -> Result<Self, ()> {
307        Ok(ScVal::Symbol(v.try_into()?))
308    }
309}
310
311#[cfg(feature = "alloc")]
312impl TryFrom<&String> for ScVal {
313    type Error = ();
314    fn try_from(v: &String) -> Result<Self, ()> {
315        Ok(ScVal::Symbol(v.try_into()?))
316    }
317}
318
319#[cfg(feature = "alloc")]
320impl TryFrom<String> for ScSymbol {
321    type Error = ();
322    fn try_from(v: String) -> Result<Self, Self::Error> {
323        Ok(ScSymbol(v.try_into().map_err(|_| ())?))
324    }
325}
326
327#[cfg(feature = "alloc")]
328impl TryFrom<&String> for ScSymbol {
329    type Error = ();
330    fn try_from(v: &String) -> Result<Self, Self::Error> {
331        Ok(ScSymbol(v.try_into().map_err(|_| ())?))
332    }
333}
334
335#[cfg(feature = "alloc")]
336impl TryFrom<&str> for ScVal {
337    type Error = ();
338    fn try_from(v: &str) -> Result<Self, ()> {
339        Ok(ScVal::Symbol(v.try_into()?))
340    }
341}
342
343#[cfg(not(feature = "alloc"))]
344impl TryFrom<&'static str> for ScVal {
345    type Error = ();
346    fn try_from(v: &'static str) -> Result<Self, ()> {
347        Ok(ScVal::Symbol(v.try_into()?))
348    }
349}
350
351#[cfg(feature = "alloc")]
352impl TryFrom<&str> for ScSymbol {
353    type Error = ();
354    fn try_from(v: &str) -> Result<Self, Self::Error> {
355        Ok(ScSymbol(v.try_into().map_err(|_| ())?))
356    }
357}
358
359#[cfg(not(feature = "alloc"))]
360impl TryFrom<&'static str> for ScSymbol {
361    type Error = ();
362    fn try_from(v: &'static str) -> Result<Self, Self::Error> {
363        Ok(ScSymbol(v.try_into().map_err(|_| ())?))
364    }
365}
366
367#[cfg(feature = "alloc")]
368impl TryFrom<ScVal> for String {
369    type Error = ();
370    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
371        if let ScVal::Symbol(s) = v {
372            // TODO: It might be worth distinguishing the error case where this
373            // is an invalid symbol with invalid characters.
374            Ok(s.0.into_utf8_string().map_err(|_| ())?)
375        } else {
376            Err(())
377        }
378    }
379}
380
381#[cfg(feature = "alloc")]
382impl TryFrom<Vec<u8>> for ScVal {
383    type Error = ();
384    fn try_from(v: Vec<u8>) -> Result<Self, ()> {
385        Ok(ScVal::Bytes(ScBytes(v.try_into().map_err(|_| ())?)))
386    }
387}
388
389#[cfg(feature = "alloc")]
390impl TryFrom<&Vec<u8>> for ScVal {
391    type Error = ();
392    fn try_from(v: &Vec<u8>) -> Result<Self, ()> {
393        Ok(ScVal::Bytes(ScBytes(v.try_into().map_err(|_| ())?)))
394    }
395}
396
397#[cfg(feature = "alloc")]
398impl TryFrom<&[u8]> for ScVal {
399    type Error = ();
400    fn try_from(v: &[u8]) -> Result<Self, ()> {
401        Ok(ScVal::Bytes(ScBytes(v.try_into().map_err(|_| ())?)))
402    }
403}
404
405#[cfg(feature = "alloc")]
406impl<const N: usize> TryFrom<[u8; N]> for ScVal {
407    type Error = ();
408    fn try_from(v: [u8; N]) -> Result<Self, ()> {
409        Ok(ScVal::Bytes(ScBytes(v.try_into().map_err(|_| ())?)))
410    }
411}
412
413#[cfg(feature = "alloc")]
414impl<const N: usize> TryFrom<&[u8; N]> for ScVal {
415    type Error = ();
416    fn try_from(v: &[u8; N]) -> Result<Self, ()> {
417        Ok(ScVal::Bytes(ScBytes(v.try_into().map_err(|_| ())?)))
418    }
419}
420
421#[cfg(not(feature = "alloc"))]
422impl TryFrom<&'static [u8]> for ScVal {
423    type Error = ();
424    fn try_from(v: &'static [u8]) -> Result<Self, ()> {
425        Ok(ScVal::Bytes(ScBytes(v.try_into().map_err(|_| ())?)))
426    }
427}
428
429#[cfg(feature = "alloc")]
430impl TryFrom<ScVal> for Vec<u8> {
431    type Error = ();
432    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
433        if let ScVal::Bytes(ScBytes(b)) = v {
434            Ok(b.into())
435        } else {
436            Err(())
437        }
438    }
439}
440
441#[cfg(feature = "alloc")]
442impl TryFrom<&ScVal> for Vec<u8> {
443    type Error = ();
444    fn try_from(v: &ScVal) -> Result<Self, Self::Error> {
445        if let ScVal::Bytes(ScBytes(b)) = v {
446            Ok(b.into())
447        } else {
448            Err(())
449        }
450    }
451}
452
453impl From<ScVec> for ScVal {
454    fn from(v: ScVec) -> Self {
455        ScVal::Vec(Some(v))
456    }
457}
458
459#[cfg(feature = "alloc")]
460impl<T: TryInto<ScVal>> TryFrom<Vec<T>> for ScVal {
461    type Error = ();
462    fn try_from(v: Vec<T>) -> Result<Self, ()> {
463        Ok(ScVal::Vec(Some(
464            v.into_iter()
465                .map(|t| <_ as TryInto<ScVal>>::try_into(t))
466                .collect::<Result<Vec<_>, _>>() // TODO: Impl conversion from Iterator to VecM in xdrgen generated code.
467                .map_err(|_| ())?
468                .try_into()
469                .map_err(|_| ())?,
470        )))
471    }
472}
473
474#[cfg(feature = "alloc")]
475impl<T: TryInto<ScVal> + Clone> TryFrom<&Vec<T>> for ScVal {
476    type Error = ();
477    fn try_from(v: &Vec<T>) -> Result<Self, ()> {
478        Ok(ScVal::Vec(Some(
479            v.iter()
480                .map(|t| <_ as TryInto<ScVal>>::try_into(t.clone()))
481                .collect::<Result<Vec<_>, _>>() // TODO: Impl conversion from Iterator to VecM in xdrgen generated code.
482                .map_err(|_| ())?
483                .try_into()
484                .map_err(|_| ())?,
485        )))
486    }
487}
488
489#[cfg(feature = "alloc")]
490impl<T: TryInto<ScVal> + Clone> TryFrom<&[T]> for ScVal {
491    type Error = ();
492    fn try_from(v: &[T]) -> Result<Self, ()> {
493        Ok(ScVal::Vec(Some(
494            v.iter()
495                .map(|t| <_ as TryInto<ScVal>>::try_into(t.clone()))
496                .collect::<Result<Vec<_>, _>>() // TODO: Impl conversion from Iterator to VecM in xdrgen generated code.
497                .map_err(|_| ())?
498                .try_into()
499                .map_err(|_| ())?,
500        )))
501    }
502}
503
504#[cfg(feature = "alloc")]
505impl<T: TryFrom<ScVal> + Clone> TryFrom<ScVal> for Vec<T> {
506    type Error = ();
507    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
508        if let ScVal::Vec(Some(v)) = v {
509            v.iter()
510                .map(|t| T::try_from(t.clone()).map_err(|_| ()))
511                .collect::<Result<Vec<T>, _>>()
512        } else {
513            Err(())
514        }
515    }
516}
517
518impl From<ScMap> for ScVal {
519    fn from(v: ScMap) -> Self {
520        ScVal::Map(Some(v))
521    }
522}
523
524impl TryFrom<ScVal> for ScMap {
525    type Error = ();
526    fn try_from(v: ScVal) -> Result<Self, Self::Error> {
527        if let ScVal::Map(Some(m)) = v {
528            Ok(m)
529        } else {
530            Err(())
531        }
532    }
533}
534
535impl<K, V> TryFrom<(K, V)> for ScMapEntry
536where
537    K: TryInto<ScVal>,
538    V: TryInto<ScVal>,
539{
540    type Error = ();
541
542    fn try_from(v: (K, V)) -> Result<Self, Self::Error> {
543        Ok(ScMapEntry {
544            key: v.0.try_into().map_err(|_| ())?,
545            val: v.1.try_into().map_err(|_| ())?,
546        })
547    }
548}
549
550// TODO: Add conversions from std::collections::HashMap, im_rcOrdMap, and other
551// popular map types to ScMap.
552
553impl<T: Into<ScVal>> From<Option<T>> for ScVal {
554    fn from(v: Option<T>) -> Self {
555        match v {
556            Some(v) => v.into(),
557            None => ().into(),
558        }
559    }
560}
561
562impl<T> From<&Option<T>> for ScVal
563where
564    T: Into<ScVal> + Clone,
565{
566    fn from(v: &Option<T>) -> Self {
567        match v {
568            Some(v) => v.clone().into(),
569            None => ().into(),
570        }
571    }
572}
573
574macro_rules! impl_for_tuple {
575    ( $count:literal $($typ:ident $idx:tt)+ ) => {
576        #[cfg(feature = "alloc")]
577        impl<$($typ),*> TryFrom<($($typ,)*)> for ScVec
578        where
579            $($typ: TryInto<ScVal>),*
580        {
581            type Error = ();
582            fn try_from(v: ($($typ,)*)) -> Result<Self, Self::Error> {
583                let vec: Vec<ScVal> = vec![$(v.$idx.try_into().map_err(|_| ())?),+];
584                Ok(ScVec(vec.try_into()?))
585            }
586        }
587
588        #[cfg(feature = "alloc")]
589        impl<$($typ),*> TryFrom<&($($typ,)*)> for ScVec
590        where
591            $($typ: TryInto<ScVal> + Clone),*
592        {
593            type Error = ();
594            fn try_from(v: &($($typ,)*)) -> Result<Self, Self::Error> {
595                let vec: Vec<ScVal> = vec![$(v.$idx.clone().try_into().map_err(|_| ())?),+];
596                Ok(ScVec(vec.try_into()?))
597            }
598        }
599
600        #[cfg(feature = "alloc")]
601        impl<$($typ),*> TryFrom<($($typ,)*)> for ScVal
602        where
603            $($typ: TryInto<ScVal>),*
604        {
605            type Error = ();
606            fn try_from(v: ($($typ,)*)) -> Result<Self, ()> {
607                Ok(ScVal::Vec(Some(<_ as TryInto<ScVec>>::try_into(v)?)))
608            }
609        }
610
611        #[cfg(feature = "alloc")]
612        impl<$($typ),*> TryFrom<&($($typ,)*)> for ScVal
613        where
614            $($typ: TryInto<ScVal> + Clone),*
615        {
616            type Error = ();
617            fn try_from(v: &($($typ,)*)) -> Result<Self, ()> {
618                Ok(ScVal::Vec(Some(<_ as TryInto<ScVec>>::try_into(v)?)))
619            }
620        }
621
622        impl<$($typ),*> TryFrom<ScVec> for ($($typ,)*)
623        where
624            // TODO: Consider removing the Clone constraint by changing the
625            // try_from to use a reference.
626            $($typ: TryFrom<ScVal> + Clone),*
627        {
628            type Error = ();
629
630            fn try_from(vec: ScVec) -> Result<Self, Self::Error> {
631                if vec.len() != $count {
632                    return Err(());
633                }
634                Ok((
635                    $({
636                        let idx: usize = $idx;
637                        let val = vec[idx].clone();
638                        $typ::try_from(val).map_err(|_| ())?
639                    },)*
640                ))
641            }
642        }
643
644        impl<$($typ),*> TryFrom<ScVal> for ($($typ,)*)
645        where
646            $($typ: TryFrom<ScVal> + Clone),*
647        {
648            type Error = ();
649
650            fn try_from(obj: ScVal) -> Result<Self, Self::Error> {
651                if let ScVal::Vec(Some(vec)) = obj {
652                    <_ as TryFrom<ScVec>>::try_from(vec)
653                } else {
654                    Err(())
655                }
656            }
657        }
658    };
659}
660
661impl_for_tuple! {  1 T0 0 }
662impl_for_tuple! {  2 T0 0 T1 1 }
663impl_for_tuple! {  3 T0 0 T1 1 T2 2 }
664impl_for_tuple! {  4 T0 0 T1 1 T2 2 T3 3 }
665impl_for_tuple! {  5 T0 0 T1 1 T2 2 T3 3 T4 4 }
666impl_for_tuple! {  6 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 }
667impl_for_tuple! {  7 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 }
668impl_for_tuple! {  8 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 }
669impl_for_tuple! {  9 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 }
670impl_for_tuple! { 10 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 }
671impl_for_tuple! { 11 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 }
672impl_for_tuple! { 12 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 }
673impl_for_tuple! { 13 T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 T12 12 }
674
675#[cfg(test)]
676mod test {
677    use super::{int128_helpers, Int128Parts, ScVal, ScVec, UInt128Parts};
678
679    #[test]
680    fn i32_pos() {
681        let v = 5;
682        let val: ScVal = v.into();
683        assert_eq!(val, ScVal::I32(5));
684        let roundtrip: i32 = val.try_into().unwrap();
685        assert_eq!(v, roundtrip);
686    }
687
688    #[test]
689    fn i32_neg() {
690        let v = -5;
691        let val: ScVal = v.into();
692        assert_eq!(val, ScVal::I32(-5));
693        let roundtrip: i32 = val.try_into().unwrap();
694        assert_eq!(v, roundtrip);
695    }
696
697    #[test]
698    fn u32() {
699        use super::ScVal;
700
701        let v = 5u32;
702        let val: ScVal = v.into();
703        assert_eq!(val, ScVal::U32(5));
704        let roundtrip: u32 = val.try_into().unwrap();
705        assert_eq!(v, roundtrip);
706    }
707
708    #[test]
709    fn i64_pos() {
710        let v = 5i64;
711        let val: ScVal = v.into();
712        assert_eq!(val, ScVal::I64(5));
713        let roundtrip: i64 = val.try_into().unwrap();
714        assert_eq!(v, roundtrip);
715    }
716
717    #[test]
718    fn i64_neg() {
719        let v = -5i64;
720        let val: ScVal = v.into();
721        assert_eq!(val, ScVal::I64(-5));
722        let roundtrip: i64 = val.try_into().unwrap();
723        assert_eq!(v, roundtrip);
724    }
725
726    #[test]
727    fn u64() {
728        let v = 5u64;
729        let val: ScVal = v.into();
730        assert_eq!(val, ScVal::U64(5));
731        let roundtrip: u64 = val.try_into().unwrap();
732        assert_eq!(v, roundtrip);
733    }
734
735    #[test]
736    fn u128() {
737        let hi = 0x1234_5678_9abc_def0u64;
738        let lo = 0xfedc_ba98_7654_3210u64;
739        let u = int128_helpers::u128_from_pieces(hi, lo);
740        assert_eq!(u, 0x1234_5678_9abc_def0_fedc_ba98_7654_3210);
741        assert_eq!(int128_helpers::u128_hi(u), hi);
742        assert_eq!(int128_helpers::u128_lo(u), lo);
743
744        let val: ScVal = u.into();
745        assert_eq!(val, ScVal::U128(UInt128Parts { hi, lo }));
746        let roundtrip: u128 = val.try_into().unwrap();
747        assert_eq!(u, roundtrip);
748    }
749
750    #[test]
751    #[allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)]
752    fn i128() {
753        let part1 = 0x00ab_cdef_9876_5432u64; // some positive int64
754        let part2 = 0xfedc_ba98_7654_3210u64; // some negative int64
755        let roundtrip = |hi: i64, lo: u64, ref_i128: i128| {
756            let i = int128_helpers::i128_from_pieces(hi, lo);
757            assert_eq!(i, ref_i128);
758            assert_eq!(int128_helpers::i128_hi(i), hi);
759            assert_eq!(int128_helpers::i128_lo(i), lo);
760
761            let val: ScVal = i.into();
762            assert_eq!(val, ScVal::I128(Int128Parts { hi, lo }));
763            let roundtrip: i128 = val.try_into().unwrap();
764            assert_eq!(i, roundtrip);
765        };
766        roundtrip(
767            part1 as i64,
768            part1,
769            0x00ab_cdef_9876_5432_00ab_cdef_9876_5432,
770        );
771        roundtrip(
772            part2 as i64,
773            part2,
774            0xfedc_ba98_7654_3210_fedc_ba98_7654_3210u128 as i128,
775        );
776        roundtrip(
777            part1 as i64,
778            part2,
779            0x00ab_cdef_9876_5432_fedc_ba98_7654_3210,
780        );
781        roundtrip(
782            part2 as i64,
783            part1,
784            0xfedc_ba98_7654_3210_00ab_cdef_9876_5432u128 as i128,
785        );
786    }
787
788    #[cfg(feature = "alloc")]
789    #[test]
790    fn binary() {
791        extern crate alloc;
792        use alloc::vec;
793
794        let v = [1, 2, 3, 4, 5];
795        let val: ScVal = v.try_into().unwrap();
796        assert_eq!(val, ScVal::Bytes(vec![1, 2, 3, 4, 5].try_into().unwrap()));
797
798        let v = &[1, 2, 3, 4, 5];
799        let val: ScVal = v.try_into().unwrap();
800        assert_eq!(val, ScVal::Bytes(vec![1, 2, 3, 4, 5].try_into().unwrap()));
801    }
802
803    #[cfg(feature = "alloc")]
804    #[test]
805    fn vec() {
806        extern crate alloc;
807        use alloc::vec;
808        use alloc::vec::Vec;
809
810        let v = vec![1, 2, 3, 4, 5];
811        let val: ScVal = v.clone().try_into().unwrap();
812        let roundtrip: Vec<i32> = val.try_into().unwrap();
813        assert_eq!(v, roundtrip);
814
815        let v = vec![vec![true], vec![false]];
816        let val: ScVal = v.clone().try_into().unwrap();
817        let roundtrip: Vec<Vec<bool>> = val.try_into().unwrap();
818        assert_eq!(v, roundtrip);
819    }
820
821    #[cfg(feature = "alloc")]
822    #[test]
823    fn tuple() {
824        extern crate alloc;
825        use alloc::vec;
826        use alloc::vec::Vec;
827        let v = (1i32, 2i64, vec![true, false]);
828        let val: ScVal = v.clone().try_into().unwrap();
829        let roundtrip: (i32, i64, Vec<bool>) = val.try_into().unwrap();
830        assert_eq!(v, roundtrip);
831    }
832
833    #[cfg(feature = "alloc")]
834    #[test]
835    fn tuple_refs() {
836        extern crate alloc;
837        use alloc::vec;
838        use alloc::vec::Vec;
839        let v = &(1i32, 2i64, vec![true, false]);
840        let val: ScVal = v.try_into().unwrap();
841        let roundtrip: (i32, i64, Vec<bool>) = val.try_into().unwrap();
842        assert_eq!(v, &roundtrip);
843    }
844
845    #[test]
846    fn option() {
847        let v: Option<i64> = Some(1);
848        let val: ScVal = v.into();
849        assert_eq!(val, ScVal::I64(1));
850
851        let v: Option<i64> = None;
852        let val: ScVal = v.into();
853        assert_eq!(val, ScVal::Void);
854    }
855
856    #[test]
857    fn scval_from() {
858        let _ = ScVal::from(ScVec::default());
859    }
860}