1#![cfg_attr(test, allow(non_upper_case_globals))]
3
4use crate::xdr::{ScError, ScVal, ScValType};
5use crate::{
6 declare_tag_based_object_wrapper, declare_tag_based_wrapper,
7 impl_tryfroms_and_tryfromvals_delegating_to_valconvert, impl_val_wrapper_base, Compare, I32Val,
8 SymbolSmall, SymbolStr, U32Val,
9};
10
11use super::{Env, Error, TryFromVal};
12use core::{cmp::Ordering, convert::Infallible, fmt::Debug, str};
13
14extern crate static_assertions as sa;
15
16#[allow(dead_code)]
20const WORD_BITS: usize = 64;
21pub(crate) const TAG_BITS: usize = 8;
22const TAG_MASK: u64 = (1u64 << TAG_BITS) - 1;
23sa::const_assert!(TAG_MASK == 0xff);
24
25#[allow(dead_code)]
26pub(crate) const BODY_BITS: usize = WORD_BITS - TAG_BITS;
27sa::const_assert!(BODY_BITS == 56);
28
29#[allow(dead_code)]
33const MAJOR_BITS: usize = 32;
34const MINOR_BITS: usize = 24;
35#[allow(dead_code)]
36const MAJOR_MASK: u64 = (1u64 << MAJOR_BITS) - 1;
37const MINOR_MASK: u64 = (1u64 << MINOR_BITS) - 1;
38sa::const_assert!(MAJOR_MASK == 0xffff_ffff);
39sa::const_assert!(MINOR_MASK == 0x00ff_ffff);
40sa::const_assert!(MAJOR_BITS + MINOR_BITS == BODY_BITS);
41
42#[repr(u8)]
47#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
48#[cfg_attr(test, derive(num_enum::TryFromPrimitive))]
49pub enum Tag {
50 False = 0,
54
55 True = 1,
57
58 Void = 2,
60
61 Error = 3,
63
64 U32Val = 4,
66
67 I32Val = 5,
69
70 U64Small = 6,
72
73 I64Small = 7,
75
76 TimepointSmall = 8,
79
80 DurationSmall = 9,
83
84 U128Small = 10,
86
87 I128Small = 11,
89
90 U256Small = 12,
92
93 I256Small = 13,
95
96 SymbolSmall = 14,
98
99 SmallCodeUpperBound = 15,
101
102 ObjectCodeLowerBound = 63,
107
108 U64Object = 64,
110
111 I64Object = 65,
113
114 TimepointObject = 66,
117
118 DurationObject = 67,
121
122 U128Object = 68,
124
125 I128Object = 69,
127
128 U256Object = 70,
130
131 I256Object = 71,
133
134 BytesObject = 72,
136
137 StringObject = 73,
139
140 SymbolObject = 74,
142
143 VecObject = 75,
145
146 MapObject = 76,
148
149 AddressObject = 77,
151
152 MuxedAddressObject = 78,
153
154 ObjectCodeUpperBound = 79,
156
157 Bad = 0x7f,
159}
160
161impl Tag {
162 #[inline(always)]
163 pub const fn val_mask() -> i64 {
164 TAG_MASK as i64
165 }
166
167 #[inline(always)]
168 pub fn val_const(&self) -> i64 {
169 *self as i64
170 }
171
172 #[inline(always)]
173 pub(crate) const fn u8_is_object(x: u8) -> bool {
174 x > (Tag::ObjectCodeLowerBound as u8) && x < (Tag::ObjectCodeUpperBound as u8)
175 }
176
177 #[inline(always)]
178 pub const fn is_object(self) -> bool {
179 Self::u8_is_object(self as u8)
180 }
181
182 #[inline(always)]
183 pub const fn from_u8(tag: u8) -> Tag {
184 const A: u8 = Tag::SmallCodeUpperBound as u8;
185 const B: u8 = Tag::ObjectCodeLowerBound as u8;
186 const C: u8 = Tag::ObjectCodeUpperBound as u8;
187 if !((tag < A) || (B < tag && tag < C)) {
188 return Tag::Bad;
189 }
190
191 unsafe { ::core::mem::transmute(tag) }
200 }
201
202 #[inline(always)]
210 pub const fn get_scval_type(&self) -> Option<ScValType> {
211 match *self {
212 Tag::False => Some(ScValType::Bool),
213 Tag::True => Some(ScValType::Bool),
214 Tag::Void => Some(ScValType::Void),
215 Tag::Error => Some(ScValType::Error),
216 Tag::U32Val => Some(ScValType::U32),
217 Tag::I32Val => Some(ScValType::I32),
218 Tag::U64Small => Some(ScValType::U64),
219 Tag::I64Small => Some(ScValType::I64),
220 Tag::TimepointSmall => Some(ScValType::Timepoint),
221 Tag::DurationSmall => Some(ScValType::Duration),
222 Tag::U128Small => Some(ScValType::U128),
223 Tag::I128Small => Some(ScValType::I128),
224 Tag::U256Small => Some(ScValType::U256),
225 Tag::I256Small => Some(ScValType::I256),
226 Tag::SymbolSmall => Some(ScValType::Symbol),
227 Tag::SmallCodeUpperBound => None,
228 Tag::ObjectCodeLowerBound => None,
229 Tag::U64Object => Some(ScValType::U64),
230 Tag::I64Object => Some(ScValType::I64),
231 Tag::TimepointObject => Some(ScValType::Timepoint),
232 Tag::DurationObject => Some(ScValType::Duration),
233 Tag::U128Object => Some(ScValType::U128),
234 Tag::I128Object => Some(ScValType::I128),
235 Tag::U256Object => Some(ScValType::U256),
236 Tag::I256Object => Some(ScValType::I256),
237 Tag::BytesObject => Some(ScValType::Bytes),
238 Tag::StringObject => Some(ScValType::String),
239 Tag::SymbolObject => Some(ScValType::Symbol),
240 Tag::VecObject => Some(ScValType::Vec),
241 Tag::MapObject => Some(ScValType::Map),
242 Tag::AddressObject => Some(ScValType::Address),
243 Tag::MuxedAddressObject => Some(ScValType::Address),
244 Tag::ObjectCodeUpperBound => None,
245 Tag::Bad => None,
246 }
247 }
248}
249
250#[repr(transparent)]
251#[derive(Copy, Clone)]
252pub struct Val(u64);
253
254impl Default for Val {
255 fn default() -> Self {
256 Self::from_void().into()
257 }
258}
259
260impl AsRef<Val> for Val {
263 fn as_ref(&self) -> &Val {
264 self
265 }
266}
267
268impl AsMut<Val> for Val {
269 fn as_mut(&mut self) -> &mut Val {
270 self
271 }
272}
273
274impl<E: Env> TryFromVal<E, Val> for Val {
275 type Error = ConversionError;
276 fn try_from_val(_env: &E, val: &Val) -> Result<Self, Self::Error> {
277 Ok(*val)
278 }
279}
280
281impl<E: Env> TryFromVal<E, &Val> for Val {
282 type Error = ConversionError;
283 fn try_from_val(_env: &E, val: &&Val) -> Result<Self, Self::Error> {
284 Ok(**val)
285 }
286}
287
288declare_tag_based_wrapper!(Void);
290
291impl From<()> for Void {
292 fn from(_value: ()) -> Self {
293 Val::VOID
294 }
295}
296
297impl<E: Env> Compare<Void> for E {
298 type Error = E::Error;
299 fn compare(&self, _a: &Void, _b: &Void) -> Result<Ordering, Self::Error> {
300 Ok(Ordering::Equal)
301 }
302}
303
304#[repr(transparent)]
305#[derive(Copy, Clone)]
306pub struct Bool(Val);
307impl_val_wrapper_base!(Bool);
308
309impl From<bool> for Bool {
310 fn from(value: bool) -> Self {
311 Val::from_bool(value)
312 }
313}
314impl From<Bool> for bool {
315 fn from(value: Bool) -> Self {
316 value.0.is_true()
317 }
318}
319
320impl ValConvert for Bool {
321 fn is_val_type(v: Val) -> bool {
322 v.is_true() || v.is_false()
323 }
324
325 unsafe fn unchecked_from_val(v: Val) -> Self {
326 Self(v)
327 }
328}
329
330impl<E: Env> Compare<Bool> for E {
331 type Error = E::Error;
332 fn compare(&self, a: &Bool, b: &Bool) -> Result<Ordering, Self::Error> {
333 let a: bool = (*a).into();
334 let b: bool = (*b).into();
335 Ok(a.cmp(&b))
336 }
337}
338
339declare_tag_based_object_wrapper!(VecObject);
341declare_tag_based_object_wrapper!(MapObject);
342declare_tag_based_object_wrapper!(AddressObject);
343declare_tag_based_object_wrapper!(MuxedAddressObject);
344
345#[derive(Debug, Eq, PartialEq)]
359pub struct ConversionError;
360
361impl From<Infallible> for ConversionError {
362 fn from(_: Infallible) -> Self {
363 unreachable!()
364 }
365}
366
367impl From<crate::xdr::Error> for ConversionError {
368 fn from(_: crate::xdr::Error) -> Self {
369 ConversionError
370 }
371}
372
373impl From<crate::Error> for ConversionError {
374 fn from(_: crate::Error) -> Self {
375 ConversionError
376 }
377}
378
379pub(crate) trait ValConvert: Into<Val> + TryFrom<Val> {
383 fn is_val_type(v: Val) -> bool;
385
386 unsafe fn unchecked_from_val(v: Val) -> Self;
393
394 #[inline(always)]
401 fn try_convert(v: Val) -> Option<Self> {
402 if Self::is_val_type(v) {
403 Some(unsafe { Self::unchecked_from_val(v) })
404 } else {
405 None
406 }
407 }
408}
409
410impl_tryfroms_and_tryfromvals_delegating_to_valconvert!(());
411impl_tryfroms_and_tryfromvals_delegating_to_valconvert!(bool);
412impl_tryfroms_and_tryfromvals_delegating_to_valconvert!(u32);
413impl_tryfroms_and_tryfromvals_delegating_to_valconvert!(i32);
414impl_tryfroms_and_tryfromvals_delegating_to_valconvert!(Error);
415
416#[cfg(feature = "wasmi")]
417pub trait WasmiMarshal: Sized {
418 fn try_marshal_from_value(v: wasmi::Value) -> Option<Self>;
419 fn marshal_from_self(self) -> wasmi::Value;
420}
421
422#[cfg(feature = "wasmi")]
423impl WasmiMarshal for Val {
424 fn try_marshal_from_value(v: wasmi::Value) -> Option<Self> {
425 if let wasmi::Value::I64(i) = v {
426 let v = Val::from_payload(i as u64);
427 if v.is_good() {
428 Some(v)
429 } else {
430 None
431 }
432 } else {
433 None
434 }
435 }
436
437 fn marshal_from_self(self) -> wasmi::Value {
438 wasmi::Value::I64(self.get_payload() as i64)
439 }
440}
441
442#[cfg(feature = "wasmi")]
443impl WasmiMarshal for u64 {
444 fn try_marshal_from_value(v: wasmi::Value) -> Option<Self> {
445 if let wasmi::Value::I64(i) = v {
446 Some(i as u64)
447 } else {
448 None
449 }
450 }
451
452 fn marshal_from_self(self) -> wasmi::Value {
453 wasmi::Value::I64(self as i64)
454 }
455}
456
457#[cfg(feature = "wasmi")]
458impl WasmiMarshal for i64 {
459 fn try_marshal_from_value(v: wasmi::Value) -> Option<Self> {
460 if let wasmi::Value::I64(i) = v {
461 Some(i)
462 } else {
463 None
464 }
465 }
466
467 fn marshal_from_self(self) -> wasmi::Value {
468 wasmi::Value::I64(self)
469 }
470}
471
472impl ValConvert for () {
476 #[inline(always)]
477 fn is_val_type(v: Val) -> bool {
478 v.has_tag(Tag::Void)
479 }
480 #[inline(always)]
481 unsafe fn unchecked_from_val(_v: Val) -> Self {}
482}
483
484impl ValConvert for bool {
485 #[inline(always)]
486 fn is_val_type(v: Val) -> bool {
487 v.has_tag(Tag::True) || v.has_tag(Tag::False)
488 }
489 #[inline(always)]
490 unsafe fn unchecked_from_val(v: Val) -> Self {
491 v.has_tag(Tag::True)
492 }
493 #[inline(always)]
494 fn try_convert(v: Val) -> Option<Self> {
495 if v.has_tag(Tag::True) {
496 Some(true)
497 } else if v.has_tag(Tag::False) {
498 Some(false)
499 } else {
500 None
501 }
502 }
503}
504
505impl ValConvert for u32 {
506 #[inline(always)]
507 fn is_val_type(v: Val) -> bool {
508 v.has_tag(Tag::U32Val)
509 }
510 #[inline(always)]
511 unsafe fn unchecked_from_val(v: Val) -> Self {
512 v.get_major()
513 }
514}
515
516impl ValConvert for i32 {
517 #[inline(always)]
518 fn is_val_type(v: Val) -> bool {
519 v.has_tag(Tag::I32Val)
520 }
521 #[inline(always)]
522 unsafe fn unchecked_from_val(v: Val) -> Self {
523 v.get_major() as i32
524 }
525}
526
527impl From<bool> for Val {
528 #[inline(always)]
529 fn from(b: bool) -> Self {
530 Val::from_bool(b).into()
531 }
532}
533
534impl From<()> for Val {
535 #[inline(always)]
536 fn from(_: ()) -> Self {
537 Val::from_void().into()
538 }
539}
540
541impl From<&()> for Val {
542 #[inline(always)]
543 fn from(_: &()) -> Self {
544 Val::from_void().into()
545 }
546}
547
548impl From<u32> for Val {
549 #[inline(always)]
550 fn from(u: u32) -> Self {
551 Val::from_u32(u).into()
552 }
553}
554
555impl From<&u32> for Val {
556 #[inline(always)]
557 fn from(u: &u32) -> Self {
558 Val::from_u32(*u).into()
559 }
560}
561
562impl From<i32> for Val {
563 #[inline(always)]
564 fn from(i: i32) -> Self {
565 Val::from_i32(i).into()
566 }
567}
568
569impl From<&i32> for Val {
570 #[inline(always)]
571 fn from(i: &i32) -> Self {
572 Val::from_i32(*i).into()
573 }
574}
575
576impl From<ScError> for Val {
577 fn from(er: ScError) -> Self {
578 let e: Error = er.into();
579 e.to_val()
580 }
581}
582
583impl From<&ScError> for Val {
584 fn from(er: &ScError) -> Self {
585 let e: Error = er.clone().into();
586 e.to_val()
587 }
588}
589
590impl Val {
593 pub const fn can_represent_scval_type(scv_ty: ScValType) -> bool {
597 match scv_ty {
598 ScValType::Bool
599 | ScValType::Void
600 | ScValType::Error
601 | ScValType::U32
602 | ScValType::I32
603 | ScValType::U64
604 | ScValType::I64
605 | ScValType::Timepoint
606 | ScValType::Duration
607 | ScValType::U128
608 | ScValType::I128
609 | ScValType::U256
610 | ScValType::I256
611 | ScValType::Bytes
612 | ScValType::String
613 | ScValType::Symbol
614 | ScValType::Vec
615 | ScValType::Map
616 | ScValType::Address => true,
617 ScValType::ContractInstance
618 | ScValType::LedgerKeyContractInstance
619 | ScValType::LedgerKeyNonce => false,
620 }
621 }
622
623 pub fn can_represent_scval(scv: &ScVal) -> bool {
627 match scv {
628 ScVal::Vec(None) => return false,
631 ScVal::Map(None) => return false,
632 _ => Self::can_represent_scval_type(scv.discriminant()),
633 }
634 }
635
636 pub fn can_represent_scval_recursive(scv: &ScVal) -> bool {
639 match scv {
640 ScVal::Vec(None) => return false,
642 ScVal::Map(None) => return false,
643 ScVal::Vec(Some(v)) => {
644 return v.0.iter().all(|x| Val::can_represent_scval_recursive(x))
645 }
646 ScVal::Map(Some(m)) => {
647 return m.0.iter().all(|e| {
648 Val::can_represent_scval_recursive(&e.key)
649 && Val::can_represent_scval_recursive(&e.val)
650 })
651 }
652 _ => Self::can_represent_scval_type(scv.discriminant()),
653 }
654 }
655
656 pub fn is_good(self) -> bool {
660 match self.get_tag() {
661 Tag::Bad
664 | Tag::SmallCodeUpperBound
665 | Tag::ObjectCodeLowerBound
666 | Tag::ObjectCodeUpperBound => false,
667 Tag::True | Tag::False | Tag::Void => self.has_body(0),
668 Tag::I32Val | Tag::U32Val => self.has_minor(0),
669 Tag::Error => ScError::try_from(unsafe { Error::unchecked_from_val(self) }).is_ok(),
670 Tag::SymbolSmall => SymbolSmall::try_from_body(self.get_body()).is_ok(),
671 Tag::U64Small
672 | Tag::I64Small
673 | Tag::TimepointSmall
674 | Tag::DurationSmall
675 | Tag::U128Small
676 | Tag::I128Small
677 | Tag::U256Small
678 | Tag::I256Small => true,
679 Tag::U64Object
680 | Tag::I64Object
681 | Tag::TimepointObject
682 | Tag::DurationObject
683 | Tag::U128Object
684 | Tag::I128Object
685 | Tag::U256Object
686 | Tag::I256Object
687 | Tag::BytesObject
688 | Tag::StringObject
689 | Tag::SymbolObject
690 | Tag::VecObject
691 | Tag::MapObject
692 | Tag::AddressObject
693 | Tag::MuxedAddressObject => self.has_minor(0),
694 }
695 }
696
697 #[inline(always)]
698 pub const fn get_payload(self) -> u64 {
699 self.0
700 }
701
702 #[inline(always)]
703 pub const fn from_payload(x: u64) -> Self {
704 Self(x)
705 }
706
707 #[inline(always)]
708 pub const fn shallow_eq(&self, other: &Self) -> bool {
709 self.0 == other.0
710 }
711
712 #[inline(always)]
713 const fn get_tag_u8(self) -> u8 {
714 (self.0 & TAG_MASK) as u8
715 }
716
717 #[inline(always)]
718 pub const fn get_tag(self) -> Tag {
719 let tag = self.get_tag_u8();
720 Tag::from_u8(tag)
721 }
722
723 #[inline(always)]
724 pub(crate) const fn get_body(self) -> u64 {
725 self.0 >> TAG_BITS
726 }
727
728 #[inline(always)]
729 pub(crate) const fn has_body(self, body: u64) -> bool {
730 self.get_body() == body
731 }
732
733 #[inline(always)]
734 pub(crate) const fn get_signed_body(self) -> i64 {
735 (self.0 as i64) >> TAG_BITS
736 }
737
738 #[inline(always)]
739 pub(crate) const fn has_tag(self, tag: Tag) -> bool {
740 self.get_tag_u8() == tag as u8
741 }
742
743 #[inline(always)]
744 pub(crate) const unsafe fn from_body_and_tag(body: u64, tag: Tag) -> Val {
747 Val((body << TAG_BITS) | (tag as u64))
748 }
749
750 #[inline(always)]
751 pub(crate) const unsafe fn from_major_minor_and_tag(major: u32, minor: u32, tag: Tag) -> Val {
753 let major = major as u64;
754 let minor = minor as u64;
755 Self::from_body_and_tag((major << MINOR_BITS) | minor, tag)
756 }
757
758 #[inline(always)]
759 pub(crate) const fn has_minor(self, minor: u32) -> bool {
760 self.get_minor() == minor
761 }
762
763 #[inline(always)]
764 pub(crate) const fn has_major(self, major: u32) -> bool {
765 self.get_major() == major
766 }
767
768 #[inline(always)]
769 pub(crate) const fn get_minor(self) -> u32 {
770 (self.get_body() & MINOR_MASK) as u32
771 }
772
773 #[inline(always)]
774 pub(crate) const fn get_major(self) -> u32 {
775 (self.get_body() >> MINOR_BITS) as u32
776 }
777
778 #[inline(always)]
779 pub const fn is_object(self) -> bool {
780 Tag::u8_is_object(self.get_tag_u8())
781 }
782
783 #[inline(always)]
784 pub const fn from_void() -> Void {
785 unsafe { Void(Val::from_body_and_tag(0, Tag::Void)) }
786 }
787
788 #[inline(always)]
789 pub const fn from_bool(b: bool) -> Bool {
790 let tag = if b { Tag::True } else { Tag::False };
791 unsafe { Bool(Val::from_body_and_tag(0, tag)) }
792 }
793
794 #[inline(always)]
795 pub const fn is_void(self) -> bool {
796 self.shallow_eq(&Self::VOID.0)
797 }
798
799 #[inline(always)]
800 pub const fn is_true(self) -> bool {
801 self.shallow_eq(&Self::TRUE.0)
802 }
803
804 #[inline(always)]
805 pub const fn is_false(self) -> bool {
806 self.shallow_eq(&Self::FALSE.0)
807 }
808}
809
810impl Val {
811 pub const I32_ZERO: I32Val = Val::from_i32(0);
812 pub const I32_MIN: I32Val = Val::from_i32(i32::MIN);
813 pub const I32_MAX: I32Val = Val::from_i32(i32::MAX);
814
815 pub const U32_ZERO: U32Val = Val::from_u32(0);
816 pub const U32_ONE: U32Val = Val::from_u32(1);
817 pub const U32_MIN: U32Val = Val::from_u32(u32::MIN);
818 pub const U32_MAX: U32Val = Val::from_u32(u32::MAX);
819
820 pub const VOID: Void = Val::from_void();
821
822 pub const TRUE: Bool = Val::from_bool(true);
823 pub const FALSE: Bool = Val::from_bool(false);
824}
825
826impl Debug for Val {
827 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
828 fn fmt_obj(name: &str, r: &Val, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
829 write!(f, "{}(obj#{})", name, r.get_major())
830 }
831
832 match self.get_tag() {
833 Tag::U32Val => write!(f, "U32({})", self.get_major()),
834 Tag::I32Val => write!(f, "I32({})", self.get_major() as i32),
835 Tag::False => write!(f, "False"),
836 Tag::True => write!(f, "True"),
837 Tag::Void => write!(f, "Void"),
838 Tag::Error => unsafe { <Error as ValConvert>::unchecked_from_val(*self) }.fmt(f),
839 Tag::U64Small => write!(f, "U64({})", self.get_body()),
840 Tag::I64Small => write!(f, "I64({})", self.get_signed_body()),
841 Tag::TimepointSmall => write!(f, "Timepoint({})", self.get_body()),
842 Tag::DurationSmall => write!(f, "Duration({})", self.get_body()),
843 Tag::U128Small => write!(f, "U128({})", self.get_body()),
845 Tag::I128Small => write!(f, "I128({})", { self.get_signed_body() }),
846 Tag::U256Small => write!(f, "U256({})", self.get_body()),
848 Tag::I256Small => write!(f, "I256({})", { self.get_signed_body() }),
849 Tag::SymbolSmall => {
850 let ss: SymbolStr =
851 unsafe { <SymbolSmall as ValConvert>::unchecked_from_val(*self) }.into();
852 let s: &str = ss.as_ref();
857 write!(f, "Symbol({})", s)
858 }
859
860 Tag::U64Object => fmt_obj("U64", self, f),
861 Tag::I64Object => fmt_obj("I64", self, f),
862 Tag::TimepointObject => fmt_obj("Timepoint", self, f),
863 Tag::DurationObject => fmt_obj("Duration", self, f),
864 Tag::U128Object => fmt_obj("U128", self, f),
865 Tag::I128Object => fmt_obj("I128", self, f),
866 Tag::U256Object => fmt_obj("U256", self, f),
867 Tag::I256Object => fmt_obj("I256", self, f),
868 Tag::BytesObject => fmt_obj("Bytes", self, f),
869 Tag::StringObject => fmt_obj("String", self, f),
870 Tag::SymbolObject => fmt_obj("Symbol", self, f),
871 Tag::VecObject => fmt_obj("Vec", self, f),
872 Tag::MapObject => fmt_obj("Map", self, f),
873 Tag::AddressObject => fmt_obj("Address", self, f),
874 Tag::MuxedAddressObject => fmt_obj("MuxedAddress", self, f),
875
876 Tag::Bad
877 | Tag::SmallCodeUpperBound
878 | Tag::ObjectCodeLowerBound
879 | Tag::ObjectCodeUpperBound => {
880 write!(
881 f,
882 "Bad(tag={:x},body={:x})",
883 self.get_tag_u8(),
884 self.get_body()
885 )
886 }
887 }
888 }
889}
890
891#[test]
892#[cfg(feature = "std")]
893fn test_debug() {
894 use super::{Error, Object, SymbolSmall};
895 use crate::{
896 xdr::{ScError, ScErrorCode},
897 I64Small, U64Small,
898 };
899 assert_eq!(format!("{:?}", Val::from_void()), "Void");
900 assert_eq!(format!("{:?}", Val::from_bool(true)), "True");
901 assert_eq!(format!("{:?}", Val::from_bool(false)), "False");
902 assert_eq!(format!("{:?}", Val::from_i32(10)), "I32(10)");
903 assert_eq!(format!("{:?}", Val::from_i32(-10)), "I32(-10)");
904 assert_eq!(format!("{:?}", Val::from_u32(10)), "U32(10)");
905 assert_eq!(format!("{:?}", I64Small::try_from(10).unwrap()), "I64(10)");
906 assert_eq!(
907 format!("{:?}", I64Small::try_from(-10).unwrap()),
908 "I64(-10)"
909 );
910 assert_eq!(format!("{:?}", U64Small::try_from(10).unwrap()), "U64(10)");
911 assert_eq!(
912 format!("{:?}", SymbolSmall::try_from_str("hello").unwrap()),
913 "Symbol(hello)"
914 );
915 assert_eq!(
916 format!("{:?}", Object::from_handle_and_tag(7, Tag::VecObject)),
917 "Vec(obj#7)"
918 );
919 assert_eq!(
920 format!(
921 "{:?}",
922 Error::from_scerror(ScError::Value(ScErrorCode::InvalidInput))
923 ),
924 "Error(Value, InvalidInput)"
925 );
926}
927
928#[test]
934fn test_tag_from_u8() {
935 use num_enum::TryFromPrimitive;
936
937 for i in 0_u8..=255 {
938 let expected_tag = Tag::try_from_primitive(i);
939 let actual_tag = Tag::from_u8(i);
940 match expected_tag {
941 Ok(
942 Tag::SmallCodeUpperBound | Tag::ObjectCodeLowerBound | Tag::ObjectCodeUpperBound,
943 ) => {
944 assert_eq!(actual_tag, Tag::Bad);
945 }
946 Ok(expected_tag) => {
947 assert_eq!(expected_tag, actual_tag);
948 let i_again = actual_tag as u8;
949 assert_eq!(i, i_again);
950 }
951 Err(_) => {
952 assert_eq!(actual_tag, Tag::Bad);
953 }
954 }
955 }
956}