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