1use std::borrow::Cow;
5use std::fmt::Write as _;
6use std::str;
7
8use async_trait::async_trait;
9use base64::engine::Engine;
10use chrono::DateTime;
11use move_core_types::account_address::AccountAddress;
12use move_core_types::annotated_value as A;
13use move_core_types::annotated_value::MoveTypeLayout;
14use move_core_types::language_storage::StructTag;
15use move_core_types::language_storage::TypeTag;
16use move_core_types::u256::U256;
17use serde::Serialize;
18use serde::ser::SerializeSeq as _;
19use serde::ser::SerializeTuple as _;
20use serde::ser::SerializeTupleVariant;
21use sui_types::base_types::ObjectID;
22use sui_types::base_types::RESOLVED_UTF8_STR;
23use sui_types::base_types::SuiAddress;
24use sui_types::base_types::move_ascii_str_layout;
25use sui_types::base_types::move_utf8_str_layout;
26use sui_types::base_types::type_name_layout;
27use sui_types::base_types::url_layout;
28use sui_types::derived_object::derive_object_id;
29use sui_types::dynamic_field::DynamicFieldInfo;
30use sui_types::dynamic_field::derive_dynamic_field_id;
31use sui_types::id::ID;
32use sui_types::id::UID;
33use sui_types::object::rpc_visitor as RV;
34use sui_types::object::rpc_visitor::Meter as _;
35
36use crate::v2::error::FormatError;
37use crate::v2::parser::Base64Modifier;
38use crate::v2::parser::Transform;
39use crate::v2::writer;
40
41#[async_trait]
48pub trait Store: Sync {
49 async fn latest(&self, id: AccountAddress)
50 -> anyhow::Result<Option<(MoveTypeLayout, Vec<u8>)>>;
51
52 async fn scoped(
53 &self,
54 id: AccountAddress,
55 ) -> anyhow::Result<Option<(MoveTypeLayout, Vec<u8>)>> {
56 self.latest(id).await
57 }
58}
59
60#[derive(Clone)]
62pub enum Strand<'s> {
63 Text(&'s str),
64 Value {
65 offset: usize,
66 value: Value<'s>,
67 transform: Option<Transform>,
68 },
69}
70
71#[derive(Clone)]
73pub enum Value<'s> {
74 Address(Address),
75 Bool(bool),
76 Bytes(Cow<'s, [u8]>),
77 Enum(Enum<'s>),
78 Slice(Slice<'s>),
79 String(Cow<'s, [u8]>),
80 Struct(Struct<'s>),
81 U8(u8),
82 U16(u16),
83 U32(u32),
84 U64(u64),
85 U128(u128),
86 U256(U256),
87 Vector(Vector<'s>),
88}
89
90#[derive(Clone, Copy)]
91pub struct Address {
92 pub(crate) bytes: AccountAddress,
93
94 pub(crate) scoped: bool,
97}
98
99#[derive(Debug, PartialEq, Eq)]
101pub enum Atom<'s> {
102 Address(AccountAddress),
103 Bool(bool),
104 Bytes(Cow<'s, [u8]>),
105 U8(u8),
106 U16(u16),
107 U32(u32),
108 U64(u64),
109 U128(u128),
110 U256(U256),
111}
112
113pub enum Accessor<'s> {
115 Field(&'s str),
116 Positional(u8),
117 Index(Value<'s>),
118 DFIndex(Value<'s>),
119 DOFIndex(Value<'s>),
120 Derived(Value<'s>),
121}
122
123#[derive(Copy, Clone)]
125pub struct Slice<'s> {
126 pub(crate) layout: &'s MoveTypeLayout,
127 pub(crate) bytes: &'s [u8],
128
129 pub(crate) scoped: bool,
132}
133
134#[derive(Clone)]
136pub struct OwnedSlice {
137 pub layout: MoveTypeLayout,
138 pub bytes: Vec<u8>,
139
140 pub scoped: bool,
143}
144
145#[derive(Clone)]
147pub struct Vector<'s> {
148 pub(crate) type_: Cow<'s, TypeTag>,
149 pub(crate) elements: Vec<Value<'s>>,
150}
151
152#[derive(Clone)]
154pub struct Struct<'s> {
155 pub(crate) type_: &'s StructTag,
156 pub(crate) fields: Fields<'s>,
157}
158
159#[derive(Clone)]
161pub struct Enum<'s> {
162 pub(crate) type_: &'s StructTag,
163 pub(crate) variant_name: Option<&'s str>,
164 pub(crate) variant_index: u16,
165 pub(crate) fields: Fields<'s>,
166}
167
168#[derive(Clone)]
170pub enum Fields<'s> {
171 Positional(Vec<Value<'s>>),
172 Named(Vec<(&'s str, Value<'s>)>),
173}
174
175impl Address {
176 pub(crate) fn scoped(bytes: AccountAddress) -> Self {
177 Self {
178 bytes,
179 scoped: true,
180 }
181 }
182
183 pub(crate) fn latest(bytes: AccountAddress) -> Self {
184 Self {
185 bytes,
186 scoped: false,
187 }
188 }
189}
190
191impl Value<'_> {
192 pub fn derive_dynamic_field_id(
195 &self,
196 parent: impl Into<SuiAddress>,
197 ) -> Result<ObjectID, FormatError> {
198 let bytes = bcs::to_bytes(self)?;
199 let type_ = self.type_();
200
201 Ok(derive_dynamic_field_id(parent, &type_, &bytes)?)
202 }
203
204 pub fn derive_dynamic_object_field_id(
207 &self,
208 parent: impl Into<SuiAddress>,
209 ) -> Result<ObjectID, FormatError> {
210 let bytes = bcs::to_bytes(self)?;
211 let type_ = DynamicFieldInfo::dynamic_object_field_wrapper(self.type_()).into();
212
213 Ok(derive_dynamic_field_id(parent, &type_, &bytes)?)
214 }
215
216 pub fn derive_object_id(&self, parent: impl Into<SuiAddress>) -> Result<ObjectID, FormatError> {
219 let bytes = bcs::to_bytes(self)?;
220 let type_ = self.type_();
221
222 Ok(derive_object_id(parent, &type_, &bytes)?)
223 }
224
225 pub fn type_(&self) -> TypeTag {
227 match self {
228 Value::Address(_) => TypeTag::Address,
229 Value::Bool(_) => TypeTag::Bool,
230 Value::Bytes(_) => TypeTag::Vector(Box::new(TypeTag::U8)),
231 Value::U8(_) => TypeTag::U8,
232 Value::U16(_) => TypeTag::U16,
233 Value::U32(_) => TypeTag::U32,
234 Value::U64(_) => TypeTag::U64,
235 Value::U128(_) => TypeTag::U128,
236 Value::U256(_) => TypeTag::U256,
237
238 Value::Enum(e) => e.type_.clone().into(),
239 Value::Struct(s) => s.type_.clone().into(),
240
241 Value::Slice(s) => s.layout.into(),
242
243 Value::String(_) => {
244 let (&address, module, name) = RESOLVED_UTF8_STR;
245 TypeTag::Struct(Box::new(StructTag {
246 address,
247 module: module.to_owned(),
248 name: name.to_owned(),
249 type_params: vec![],
250 }))
251 }
252
253 Value::Vector(v) => v.type_(),
254 }
255 }
256
257 pub(crate) fn format(
263 self,
264 transform: Transform,
265 w: &mut writer::StringWriter<'_>,
266 ) -> Result<(), FormatError> {
267 match transform {
268 Transform::Base64(xmod) => Atom::try_from(self)?.format_as_base64(xmod.engine(), w),
269 Transform::Bcs(xmod) => {
270 let bytes = bcs::to_bytes(&self)?;
271 Ok(write!(w, "{}", xmod.engine().encode(bytes))?)
272 }
273
274 Transform::Hex => Atom::try_from(self)?.format_as_hex(w),
275 Transform::Json => Err(FormatError::TransformInvalid("unexpected 'json' in string")),
276 Transform::Str => Atom::try_from(self)?.format_as_str(w),
277 Transform::Timestamp => Atom::try_from(self)?.format_as_timestamp(w),
278 Transform::Url => Atom::try_from(self)?.format_as_url(w),
279 }
280 }
281
282 pub(crate) fn format_json<F: RV::Format>(
287 self,
288 mut meter: writer::Meter<'_>,
289 ) -> Result<F, FormatError> {
290 match self {
291 Value::Address(a) => Ok(F::string(&mut meter, a.bytes.to_canonical_string(true))?),
292 Value::Bool(b) => Ok(F::bool(&mut meter, b)?),
293 Value::U8(n) => Ok(F::number(&mut meter, n as u32)?),
294 Value::U16(n) => Ok(F::number(&mut meter, n as u32)?),
295 Value::U32(n) => Ok(F::number(&mut meter, n)?),
296 Value::U64(n) => Ok(F::string(&mut meter, n.to_string())?),
297 Value::U128(n) => Ok(F::string(&mut meter, n.to_string())?),
298 Value::U256(n) => Ok(F::string(&mut meter, n.to_string())?),
299
300 Value::Bytes(bs) => {
301 let b64 = Base64Modifier::EMPTY.engine().encode(&bs);
302 Ok(F::string(&mut meter, b64)?)
303 }
304
305 Value::String(bs) => {
306 let s = str::from_utf8(&bs)
307 .map_err(|_| FormatError::TransformInvalid("expected utf8 bytes"))?;
308 Ok(F::string(&mut meter, s.to_owned())?)
309 }
310
311 Value::Struct(s) => s.format_json(meter),
312 Value::Enum(e) => e.format_json(meter),
313 Value::Vector(v) => v.format_json(meter),
314 Value::Slice(s) => s.format_json(meter),
315 }
316 }
317
318 pub(crate) fn as_u64(&self) -> Option<u64> {
321 use MoveTypeLayout as L;
322 use Value as V;
323
324 match self {
325 V::U8(n) => Some(*n as u64),
327 V::U16(n) => Some(*n as u64),
328 V::U32(n) => Some(*n as u64),
329 V::U64(n) => Some(*n),
330 V::U128(n) => u64::try_from(*n).ok(),
331 V::U256(n) => u64::try_from(*n).ok(),
332
333 V::Slice(Slice {
335 layout,
336 bytes: data,
337 ..
338 }) => match layout {
339 L::U8 => Some(bcs::from_bytes::<u8>(data).ok()?.into()),
340 L::U16 => Some(bcs::from_bytes::<u16>(data).ok()?.into()),
341 L::U32 => Some(bcs::from_bytes::<u32>(data).ok()?.into()),
342 L::U64 => bcs::from_bytes::<u64>(data).ok(),
343 L::U128 => bcs::from_bytes::<u128>(data).ok()?.try_into().ok(),
344 L::U256 => bcs::from_bytes::<U256>(data).ok()?.try_into().ok(),
345 L::Address | L::Bool | L::Enum(_) | L::Signer | L::Struct(_) | L::Vector(_) => None,
346 },
347
348 V::Address(_)
350 | V::Bool(_)
351 | V::Bytes(_)
352 | V::Enum(_)
353 | V::String(_)
354 | V::Struct(_)
355 | V::Vector(_) => None,
356 }
357 }
358
359 pub(crate) fn set_scope(&mut self, scope: bool) {
361 match self {
362 Value::Address(a) => a.scoped = scope,
363 Value::Slice(s) => s.scoped = scope,
364
365 _ => (),
368 }
369 }
370}
371
372impl Atom<'_> {
373 fn format_as_hex(&self, w: &mut writer::StringWriter<'_>) -> Result<(), FormatError> {
375 match self {
376 Atom::Bool(b) => write!(w, "{:02x}", *b as u8)?,
377 Atom::U8(n) => write!(w, "{n:02x}")?,
378 Atom::U16(n) => write!(w, "{n:04x}")?,
379 Atom::U32(n) => write!(w, "{n:08x}")?,
380 Atom::U64(n) => write!(w, "{n:016x}")?,
381 Atom::U128(n) => write!(w, "{n:032x}")?,
382 Atom::U256(n) => write!(w, "{n:064x}")?,
383
384 Atom::Address(a) => {
385 for b in a.into_bytes() {
386 write!(w, "{b:02x}")?;
387 }
388 }
389
390 Atom::Bytes(bs) => {
391 for b in bs.iter() {
392 write!(w, "{b:02x}")?;
393 }
394 }
395 }
396
397 Ok(())
398 }
399
400 pub(crate) fn format_as_str(
402 &self,
403 w: &mut writer::StringWriter<'_>,
404 ) -> Result<(), FormatError> {
405 match self {
406 Atom::Address(a) => write!(w, "{}", a.to_canonical_display(true))?,
407 Atom::Bool(b) => write!(w, "{b}")?,
408 Atom::U8(n) => write!(w, "{n}")?,
409 Atom::U16(n) => write!(w, "{n}")?,
410 Atom::U32(n) => write!(w, "{n}")?,
411 Atom::U64(n) => write!(w, "{n}")?,
412 Atom::U128(n) => write!(w, "{n}")?,
413 Atom::U256(n) => write!(w, "{n}")?,
414 Atom::Bytes(bs) => {
415 let s = str::from_utf8(bs)
416 .map_err(|_| FormatError::TransformInvalid("expected utf8 bytes"))?;
417 write!(w, "{s}")?;
418 }
419 }
420
421 Ok(())
422 }
423
424 fn format_as_timestamp(&self, w: &mut writer::StringWriter<'_>) -> Result<(), FormatError> {
427 let ts = self
428 .as_i64()
429 .and_then(DateTime::from_timestamp_millis)
430 .ok_or_else(|| {
431 FormatError::TransformInvalid("expected unix timestamp in milliseconds")
432 })?;
433
434 write!(w, "{ts:?}")?;
435 Ok(())
436 }
437
438 fn format_as_url(&self, w: &mut writer::StringWriter<'_>) -> Result<(), FormatError> {
440 match self {
441 Atom::Address(a) => write!(w, "{}", a.to_canonical_display(true))?,
442 Atom::Bool(b) => write!(w, "{b}")?,
443 Atom::U8(n) => write!(w, "{n}")?,
444 Atom::U16(n) => write!(w, "{n}")?,
445 Atom::U32(n) => write!(w, "{n}")?,
446 Atom::U64(n) => write!(w, "{n}")?,
447 Atom::U128(n) => write!(w, "{n}")?,
448 Atom::U256(n) => write!(w, "{n}")?,
449 Atom::Bytes(bs) => {
450 for b in bs.iter() {
451 match *b {
452 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'.' | b'_' | b'~' => {
453 write!(w, "{}", *b as char)?
454 }
455 b => write!(w, "%{b:02X}")?,
456 }
457 }
458 }
459 }
460
461 Ok(())
462 }
463
464 fn format_as_base64(
466 &self,
467 e: &impl Engine,
468 w: &mut writer::StringWriter<'_>,
469 ) -> Result<(), FormatError> {
470 let base64 = match self {
471 Atom::Address(a) => e.encode(a.into_bytes()),
472 Atom::Bool(b) => e.encode([*b as u8]),
473 Atom::U8(n) => e.encode([*n]),
474 Atom::U16(n) => e.encode(n.to_le_bytes()),
475 Atom::U32(n) => e.encode(n.to_le_bytes()),
476 Atom::U64(n) => e.encode(n.to_le_bytes()),
477 Atom::U128(n) => e.encode(n.to_le_bytes()),
478 Atom::U256(n) => e.encode(n.to_le_bytes()),
479 Atom::Bytes(bs) => e.encode(bs),
480 };
481
482 write!(w, "{base64}")?;
483 Ok(())
484 }
485
486 fn as_i64(&self) -> Option<i64> {
488 match self {
489 Atom::U8(n) => Some(*n as i64),
490 Atom::U16(n) => Some(*n as i64),
491 Atom::U32(n) => Some(*n as i64),
492 Atom::U64(n) => i64::try_from(*n).ok(),
493 Atom::U128(n) => i64::try_from(*n).ok(),
494 Atom::U256(n) => u64::try_from(*n).ok().and_then(|v| i64::try_from(v).ok()),
495 _ => None,
496 }
497 }
498}
499
500impl<'s> Accessor<'s> {
501 pub(crate) fn as_numeric_index(&self) -> Option<u64> {
506 use Accessor as A;
507
508 match self {
509 A::Index(value) => value.as_u64(),
510 A::DFIndex(_) | A::DOFIndex(_) | A::Derived(_) | A::Field(_) | A::Positional(_) => None,
512 }
513 }
514
515 pub(crate) fn as_field_name(&self) -> Option<Cow<'s, str>> {
517 use Accessor as A;
518 match self {
519 A::Field(f) => Some(Cow::Borrowed(*f)),
520 A::Positional(i) => Some(Cow::Owned(format!("pos{i}"))),
521 A::Index(_) | A::DFIndex(_) | A::DOFIndex(_) | A::Derived(_) => None,
522 }
523 }
524}
525
526impl OwnedSlice {
527 pub fn new(layout: MoveTypeLayout, bytes: Vec<u8>) -> Self {
528 Self {
529 layout,
530 bytes,
531 scoped: true,
532 }
533 }
534
535 pub(crate) fn as_slice(&self) -> Slice<'_> {
536 Slice {
537 layout: &self.layout,
538 bytes: &self.bytes,
539 scoped: self.scoped,
540 }
541 }
542}
543
544impl Slice<'_> {
545 fn format_json<F: RV::Format>(self, meter: writer::Meter<'_>) -> Result<F, FormatError> {
546 Ok(A::MoveValue::visit_deserialize(
547 self.bytes,
548 self.layout,
549 &mut RV::RpcVisitor::new(meter),
550 )?)
551 }
552}
553
554impl Value<'_> {
555 pub fn into_owned_slice(self) -> Option<OwnedSlice> {
560 let scoped = match &self {
561 Value::Slice(s) => s.scoped,
562 Value::Address(a) => a.scoped,
563 _ => false,
564 };
565
566 let layout = self.layout()?;
567 let bytes = bcs::to_bytes(&self).ok()?;
568 Some(OwnedSlice {
569 layout,
570 bytes,
571 scoped,
572 })
573 }
574
575 fn layout(&self) -> Option<MoveTypeLayout> {
580 use MoveTypeLayout as L;
581
582 match self {
583 Value::Slice(s) => Some(s.layout.clone()),
584
585 Value::Address(_) => Some(L::Address),
586 Value::Bool(_) => Some(L::Bool),
587 Value::U8(_) => Some(L::U8),
588 Value::U16(_) => Some(L::U16),
589 Value::U32(_) => Some(L::U32),
590 Value::U64(_) => Some(L::U64),
591 Value::U128(_) => Some(L::U128),
592 Value::U256(_) => Some(L::U256),
593
594 Value::Bytes(_) => Some(L::Vector(Box::new(L::U8))),
595 Value::String(_) => Some(L::Struct(Box::new(move_utf8_str_layout()))),
596
597 Value::Enum(_) | Value::Struct(_) | Value::Vector(_) => None,
599 }
600 }
601}
602
603impl Vector<'_> {
604 fn type_(&self) -> TypeTag {
605 TypeTag::Vector(Box::new(self.type_.clone().into_owned()))
606 }
607
608 fn format_json<F: RV::Format>(self, mut meter: writer::Meter<'_>) -> Result<F, FormatError> {
609 let mut elems = F::Vec::default();
610 let mut nested = meter.nest()?;
611 for e in self.elements {
612 let json = e.format_json(nested.reborrow())?;
613 F::vec_push_element(&mut nested, &mut elems, json)?;
614 }
615
616 Ok(F::vec(&mut meter, elems)?)
617 }
618}
619
620impl Struct<'_> {
621 fn format_json<F: RV::Format>(self, mut meter: writer::Meter<'_>) -> Result<F, FormatError> {
622 let mut map = F::Map::default();
623 let nested = meter.nest()?;
624 self.fields.format_json::<F>(nested, &mut map)?;
625
626 Ok(F::map(&mut meter, map)?)
627 }
628}
629
630impl Enum<'_> {
631 fn format_json<F: RV::Format>(self, mut meter: writer::Meter<'_>) -> Result<F, FormatError> {
632 let mut map = F::Map::default();
633 let mut nested = meter.nest()?;
634
635 let name = match self.variant_name {
636 Some(name) => F::string(&mut nested, name.to_owned())?,
637 None => F::number(&mut nested, self.variant_index as u32)?,
638 };
639
640 F::map_push_field(&mut nested, &mut map, "@variant".to_owned(), name)?;
641 self.fields.format_json::<F>(nested, &mut map)?;
642
643 Ok(F::map(&mut meter, map)?)
644 }
645}
646
647impl<'s> Fields<'s> {
648 pub(crate) fn get(self, accessor: &Accessor<'s>) -> Option<Value<'s>> {
651 match (self, accessor) {
652 (Fields::Positional(mut fs), Accessor::Positional(i)) => {
653 let i = *i as usize;
654 if i < fs.len() {
655 Some(fs.swap_remove(i))
656 } else {
657 None
658 }
659 }
660
661 (Fields::Named(mut fs), Accessor::Field(f)) => {
662 let i = fs.iter().position(|(n, _)| n == f)?;
663 Some(fs.swap_remove(i).1)
664 }
665
666 _ => None,
667 }
668 }
669
670 fn len(&self) -> usize {
671 match self {
672 Fields::Positional(fs) => fs.len(),
673 Fields::Named(fs) => fs.len(),
674 }
675 }
676
677 fn format_json<F: RV::Format>(
678 self,
679 mut meter: writer::Meter<'_>,
680 map: &mut F::Map,
681 ) -> Result<(), FormatError> {
682 match self {
683 Fields::Positional(values) => {
684 for (i, value) in values.into_iter().enumerate() {
685 let json = value.format_json(meter.reborrow())?;
686 F::map_push_field(&mut meter, map, format!("pos{i}"), json)?;
687 }
688 }
689
690 Fields::Named(items) => {
691 for (field, value) in items {
692 let json = value.format_json(meter.reborrow())?;
693 F::map_push_field(&mut meter, map, field.to_owned(), json)?;
694 }
695 }
696 }
697
698 Ok(())
699 }
700}
701
702impl Serialize for Value<'_> {
704 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
705 where
706 S: serde::Serializer,
707 {
708 match self {
709 Value::Address(a) => a.bytes.serialize(serializer),
710 Value::Bool(b) => b.serialize(serializer),
711 Value::Bytes(b) => b.serialize(serializer),
712 Value::Enum(e) => e.serialize(serializer),
713 Value::Slice(s) => s.serialize(serializer),
714 Value::String(s) => s.serialize(serializer),
715 Value::Struct(s) => s.serialize(serializer),
716 Value::U8(n) => n.serialize(serializer),
717 Value::U16(n) => n.serialize(serializer),
718 Value::U32(n) => n.serialize(serializer),
719 Value::U64(n) => n.serialize(serializer),
720 Value::U128(n) => n.serialize(serializer),
721 Value::U256(n) => n.serialize(serializer),
722 Value::Vector(v) => v.serialize(serializer),
723 }
724 }
725}
726
727impl Serialize for Slice<'_> {
730 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
731 where
732 S: serde::Serializer,
733 {
734 let mut s = serializer.serialize_tuple(self.bytes.len())?;
735 for b in self.bytes {
736 s.serialize_element(b)?;
737 }
738
739 s.end()
740 }
741}
742
743impl Serialize for Vector<'_> {
744 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
745 where
746 S: serde::Serializer,
747 {
748 let mut s = serializer.serialize_seq(Some(self.elements.len()))?;
749 for e in &self.elements {
750 s.serialize_element(e)?;
751 }
752
753 s.end()
754 }
755}
756
757impl Serialize for Struct<'_> {
758 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
759 where
760 S: serde::Serializer,
761 {
762 let mut s = serializer.serialize_tuple(self.fields.len())?;
766
767 match &self.fields {
768 Fields::Positional(fs) if fs.is_empty() => {
771 s.serialize_element(&false)?;
772 }
773
774 Fields::Named(fs) if fs.is_empty() => {
775 s.serialize_element(&false)?;
776 }
777
778 Fields::Positional(fs) => {
779 for f in fs {
780 s.serialize_element(f)?;
781 }
782 }
783 Fields::Named(fs) => {
784 for (_, f) in fs {
785 s.serialize_element(f)?;
786 }
787 }
788 }
789
790 s.end()
791 }
792}
793
794impl Serialize for Enum<'_> {
795 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
796 where
797 S: serde::Serializer,
798 {
799 let mut s = serializer.serialize_tuple_variant(
801 "",
802 self.variant_index as u32,
803 "",
804 self.fields.len(),
805 )?;
806
807 match &self.fields {
808 Fields::Positional(fs) => {
809 for f in fs {
810 s.serialize_field(f)?;
811 }
812 }
813 Fields::Named(fs) => {
814 for (_, f) in fs {
815 s.serialize_field(f)?;
816 }
817 }
818 }
819
820 s.end()
821 }
822}
823
824impl<'s> TryFrom<Value<'s>> for Atom<'s> {
825 type Error = FormatError;
826
827 fn try_from(value: Value<'s>) -> Result<Atom<'s>, FormatError> {
828 use Atom as A;
829 use MoveTypeLayout as L;
830 use TypeTag as T;
831 use Value as V;
832
833 Ok(match value {
834 V::Address(a) => A::Address(a.bytes),
835 V::Bool(b) => A::Bool(b),
836 V::U8(n) => A::U8(n),
837 V::U16(n) => A::U16(n),
838 V::U32(n) => A::U32(n),
839 V::U64(n) => A::U64(n),
840 V::U128(n) => A::U128(n),
841 V::U256(n) => A::U256(n),
842
843 V::Bytes(bs) | V::String(bs) => A::Bytes(bs),
845
846 V::Enum(_) => return Err(FormatError::TransformInvalid("unexpected enum")),
847 V::Struct(_) => return Err(FormatError::TransformInvalid("unexpected struct")),
848
849 V::Vector(Vector { type_, elements }) => {
851 if *type_ != T::U8 {
852 return Err(FormatError::TransformInvalid("unexpected vector"));
853 }
854
855 let bytes: Result<Vec<_>, _> = elements
856 .into_iter()
857 .map(|e| match e {
858 V::U8(b) => Ok(b),
859 V::Slice(Slice { layout, bytes, .. }) if layout == &L::U8 => {
860 Ok(bcs::from_bytes(bytes)?)
861 }
862 _ => Err(FormatError::TransformInvalid("unexpected vector")),
863 })
864 .collect();
865
866 A::Bytes(Cow::Owned(bytes?))
867 }
868
869 V::Slice(Slice { layout, bytes, .. }) => match layout {
870 L::Address => A::Address(bcs::from_bytes(bytes)?),
871 L::Bool => A::Bool(bcs::from_bytes(bytes)?),
872 L::U8 => A::U8(bcs::from_bytes(bytes)?),
873 L::U16 => A::U16(bcs::from_bytes(bytes)?),
874 L::U32 => A::U32(bcs::from_bytes(bytes)?),
875 L::U64 => A::U64(bcs::from_bytes(bytes)?),
876 L::U128 => A::U128(bcs::from_bytes(bytes)?),
877 L::U256 => A::U256(bcs::from_bytes(bytes)?),
878
879 L::Vector(layout) if layout.as_ref() == &L::U8 => {
880 A::Bytes(Cow::Borrowed(bcs::from_bytes(bytes)?))
881 }
882
883 L::Struct(layout)
884 if [
885 move_ascii_str_layout(),
886 move_utf8_str_layout(),
887 type_name_layout(),
888 url_layout(),
889 ]
890 .contains(layout.as_ref()) =>
891 {
892 A::Bytes(Cow::Borrowed(bcs::from_bytes(bytes)?))
893 }
894
895 L::Struct(layout) if [UID::layout(), ID::layout()].contains(layout.as_ref()) => {
896 A::Address(bcs::from_bytes(bytes)?)
897 }
898
899 L::Signer => return Err(FormatError::TransformInvalid("unexpected signer")),
900 L::Enum(_) => return Err(FormatError::TransformInvalid("unexpected enum")),
901 L::Struct(_) => return Err(FormatError::TransformInvalid("unexpected struct")),
902 L::Vector(_) => return Err(FormatError::TransformInvalid("unexpected vector")),
903 },
904 })
905 }
906}
907
908#[cfg(test)]
909pub(crate) mod tests {
910 use std::collections::BTreeMap;
911 use std::str::FromStr;
912 use std::sync::atomic::AtomicUsize;
913
914 use itertools::Itertools;
915 use move_core_types::annotated_value::MoveEnumLayout;
916 use move_core_types::annotated_value::MoveFieldLayout;
917 use move_core_types::annotated_value::MoveStructLayout;
918 use move_core_types::annotated_value::MoveTypeLayout as L;
919 use move_core_types::identifier::Identifier;
920 use serde_json::Value as Json;
921 use serde_json::json;
922 use sui_types::MOVE_STDLIB_ADDRESS;
923 use sui_types::base_types::STD_ASCII_MODULE_NAME;
924 use sui_types::base_types::STD_ASCII_STRUCT_NAME;
925 use sui_types::derived_object::derive_object_id;
926 use sui_types::dynamic_field::DynamicFieldInfo;
927 use sui_types::dynamic_field::Field;
928 use sui_types::dynamic_field::derive_dynamic_field_id;
929 use sui_types::id::ID;
930 use sui_types::id::UID;
931
932 use super::*;
933
934 #[derive(Default, Clone)]
936 pub struct MockStore {
937 data: BTreeMap<AccountAddress, (MoveTypeLayout, Vec<u8>)>,
938 }
939
940 impl MockStore {
941 pub(crate) fn with_dynamic_field<N: Serialize, V: Serialize>(
946 mut self,
947 parent: AccountAddress,
948 name: N,
949 name_layout: MoveTypeLayout,
950 value: V,
951 value_layout: MoveTypeLayout,
952 ) -> Self {
953 use Identifier as I;
954 use MoveFieldLayout as F;
955 use MoveStructLayout as S;
956
957 let name_bytes = bcs::to_bytes(&name).unwrap();
958 let name_type = TypeTag::from(&name_layout);
959 let value_type = TypeTag::from(&value_layout);
960 let df_id = derive_dynamic_field_id(parent, &name_type, &name_bytes).unwrap();
961
962 let bytes = bcs::to_bytes(&Field {
963 id: UID::new(df_id),
964 name,
965 value,
966 })
967 .unwrap();
968
969 let layout = L::Struct(Box::new(S {
970 type_: DynamicFieldInfo::dynamic_field_type(name_type, value_type),
971 fields: vec![
972 F::new(I::new("id").unwrap(), L::Struct(Box::new(UID::layout()))),
973 F::new(I::new("name").unwrap(), name_layout),
974 F::new(I::new("value").unwrap(), value_layout),
975 ],
976 }));
977
978 self.data.insert(df_id.into(), (layout, bytes));
979 self
980 }
981
982 pub(crate) fn with_dynamic_object_field<N: Serialize, V: Serialize>(
988 mut self,
989 parent: AccountAddress,
990 name: N,
991 name_layout: MoveTypeLayout,
992 value: V,
993 value_layout: MoveTypeLayout,
994 ) -> Self {
995 use AccountAddress as A;
996 use Identifier as I;
997 use MoveFieldLayout as F;
998 use MoveStructLayout as S;
999
1000 let name_bytes = bcs::to_bytes(&name).unwrap();
1001 let value_bytes = bcs::to_bytes(&value).unwrap();
1002 let name_type = TypeTag::from(&name_layout);
1003 let wrap_type = DynamicFieldInfo::dynamic_object_field_wrapper(name_type);
1004 let val_id = A::from_bytes(&value_bytes[0..AccountAddress::LENGTH]).unwrap();
1005 let dof_id =
1006 derive_dynamic_field_id(parent, &wrap_type.clone().into(), &name_bytes).unwrap();
1007
1008 let field_bytes = bcs::to_bytes(&Field {
1009 id: UID::new(dof_id),
1010 name,
1011 value: val_id,
1012 })
1013 .unwrap();
1014
1015 let wrapper_layout = L::Struct(Box::new(S {
1016 type_: wrap_type.clone(),
1017 fields: vec![F::new(I::new("name").unwrap(), name_layout)],
1018 }));
1019
1020 let field_layout = L::Struct(Box::new(S {
1021 type_: DynamicFieldInfo::dynamic_field_type(wrap_type.into(), ID::type_().into()),
1022 fields: vec![
1023 F::new(I::new("id").unwrap(), L::Struct(Box::new(UID::layout()))),
1024 F::new(I::new("name").unwrap(), wrapper_layout),
1025 F::new(I::new("value").unwrap(), L::Struct(Box::new(ID::layout()))),
1026 ],
1027 }));
1028
1029 self.data.insert(dof_id.into(), (field_layout, field_bytes));
1030 self.data.insert(val_id, (value_layout, value_bytes));
1031 self
1032 }
1033
1034 pub(crate) fn with_derived_object<N: Serialize, V: Serialize>(
1036 mut self,
1037 parent: AccountAddress,
1038 name: N,
1039 name_layout: MoveTypeLayout,
1040 value: V,
1041 value_layout: MoveTypeLayout,
1042 ) -> Self {
1043 let name_bytes = bcs::to_bytes(&name).unwrap();
1044 let value_bytes = bcs::to_bytes(&value).unwrap();
1045 let name_type = TypeTag::from(&name_layout);
1046 let id = derive_object_id(parent, &name_type, &name_bytes).unwrap();
1047
1048 self.data.insert(id.into(), (value_layout, value_bytes));
1049 self
1050 }
1051 }
1052
1053 #[async_trait]
1054 impl Store for MockStore {
1055 async fn latest(
1056 &self,
1057 id: AccountAddress,
1058 ) -> anyhow::Result<Option<(MoveTypeLayout, Vec<u8>)>> {
1059 Ok(self.data.get(&id).cloned())
1060 }
1061 }
1062
1063 pub fn struct_(type_: &str, fields: Vec<(&str, MoveTypeLayout)>) -> MoveTypeLayout {
1064 let type_: StructTag = type_.parse().unwrap();
1065 let fields = fields
1066 .into_iter()
1067 .map(|(name, layout)| MoveFieldLayout::new(Identifier::new(name).unwrap(), layout))
1068 .collect();
1069
1070 MoveTypeLayout::Struct(Box::new(MoveStructLayout { type_, fields }))
1071 }
1072
1073 pub fn enum_(
1074 type_: &str,
1075 variants: Vec<(&str, Vec<(&str, MoveTypeLayout)>)>,
1076 ) -> MoveTypeLayout {
1077 let type_: StructTag = type_.parse().unwrap();
1078 let variants = variants
1079 .into_iter()
1080 .enumerate()
1081 .map(|(tag, (name, fields))| {
1082 let fields = fields
1083 .into_iter()
1084 .map(|(name, layout)| {
1085 MoveFieldLayout::new(Identifier::new(name).unwrap(), layout)
1086 })
1087 .collect();
1088
1089 ((Identifier::new(name).unwrap(), tag as u16), fields)
1090 })
1091 .collect();
1092
1093 MoveTypeLayout::Enum(Box::new(MoveEnumLayout { type_, variants }))
1094 }
1095
1096 pub fn vector_(layout: MoveTypeLayout) -> MoveTypeLayout {
1097 MoveTypeLayout::Vector(Box::new(layout))
1098 }
1099
1100 pub fn optional_(layout: MoveTypeLayout) -> MoveTypeLayout {
1101 let type_ = TypeTag::from(&layout);
1102 struct_(
1103 &format!("0x1::option::Option<{type_}>"),
1104 vec![("vec", vector_(layout))],
1105 )
1106 }
1107
1108 pub fn vec_map(key: MoveTypeLayout, value: MoveTypeLayout) -> MoveTypeLayout {
1109 let key_type = TypeTag::from(&key);
1110 let value_type = TypeTag::from(&value);
1111
1112 struct_(
1113 &format!("0x2::vec_map::VecMap<{key_type}, {value_type}>"),
1114 vec![(
1115 "contents",
1116 vector_(struct_(
1117 &format!("0x2::vec_map::Entry<{key_type}, {value_type}>"),
1118 vec![("key", key), ("value", value)],
1119 )),
1120 )],
1121 )
1122 }
1123
1124 #[test]
1125 fn test_slice_serialize_roundtrip() {
1126 let bytes = &[0x01, 0x02, 0x03, 0x04];
1127 let slice = Slice {
1128 layout: &L::U64,
1129 bytes,
1130 scoped: false,
1131 };
1132
1133 let serialized = bcs::to_bytes(&slice).unwrap();
1134 assert_eq!(serialized, bytes);
1135 }
1136
1137 #[test]
1138 fn test_serialize_bool() {
1139 assert_eq!(
1140 bcs::to_bytes(&Value::Bool(true)).unwrap(),
1141 bcs::to_bytes(&true).unwrap()
1142 );
1143 assert_eq!(
1144 bcs::to_bytes(&Value::Bool(false)).unwrap(),
1145 bcs::to_bytes(&false).unwrap()
1146 );
1147 }
1148
1149 #[test]
1150 fn test_serialize_u8() {
1151 assert_eq!(
1152 bcs::to_bytes(&Value::U8(42)).unwrap(),
1153 bcs::to_bytes(&42u8).unwrap()
1154 );
1155 }
1156
1157 #[test]
1158 fn test_serialize_u16() {
1159 assert_eq!(
1160 bcs::to_bytes(&Value::U16(1234)).unwrap(),
1161 bcs::to_bytes(&1234u16).unwrap()
1162 );
1163 }
1164
1165 #[test]
1166 fn test_serialize_u32() {
1167 assert_eq!(
1168 bcs::to_bytes(&Value::U32(123456)).unwrap(),
1169 bcs::to_bytes(&123456u32).unwrap()
1170 );
1171 }
1172
1173 #[test]
1174 fn test_serialize_u64() {
1175 assert_eq!(
1176 bcs::to_bytes(&Value::U64(12345678901234)).unwrap(),
1177 bcs::to_bytes(&12345678901234u64).unwrap()
1178 );
1179 }
1180
1181 #[test]
1182 fn test_serialize_u128() {
1183 assert_eq!(
1184 bcs::to_bytes(&Value::U128(123456789012345678901234567890)).unwrap(),
1185 bcs::to_bytes(&123456789012345678901234567890u128).unwrap()
1186 );
1187 }
1188
1189 #[test]
1190 fn test_serialize_u256() {
1191 let val = U256::from(42u64);
1192 assert_eq!(
1193 bcs::to_bytes(&Value::U256(val)).unwrap(),
1194 bcs::to_bytes(&val).unwrap()
1195 );
1196 }
1197
1198 #[test]
1199 fn test_serialize_address() {
1200 let addr: AccountAddress = "0x1".parse().unwrap();
1201 assert_eq!(
1202 bcs::to_bytes(&Value::Address(Address::latest(addr))).unwrap(),
1203 bcs::to_bytes(&addr).unwrap()
1204 );
1205 }
1206
1207 #[test]
1208 fn test_serialize_string() {
1209 assert_eq!(
1210 bcs::to_bytes(&Value::String(Cow::Borrowed("hello".as_bytes()))).unwrap(),
1211 bcs::to_bytes("hello").unwrap()
1212 );
1213 }
1214
1215 #[test]
1216 fn test_serialize_bytes() {
1217 let bytes = vec![1u8, 2, 3, 4, 5];
1218 assert_eq!(
1219 bcs::to_bytes(&Value::Bytes(Cow::Borrowed(&bytes))).unwrap(),
1220 bcs::to_bytes(&bytes).unwrap()
1221 );
1222 }
1223
1224 #[test]
1225 fn test_serialize_positional_struct() {
1226 let type_ = &"0x2::foo::Bar".parse().unwrap();
1227 let struct_ = Value::Struct(Struct {
1228 type_,
1229 fields: Fields::Positional(vec![
1230 Value::U64(42),
1231 Value::Bool(true),
1232 Value::String(Cow::Borrowed("test".as_bytes())),
1233 ]),
1234 });
1235
1236 assert_eq!(
1237 bcs::to_bytes(&struct_).unwrap(),
1238 bcs::to_bytes(&(42u64, true, "test")).unwrap()
1239 );
1240 }
1241
1242 #[test]
1243 fn test_serialize_named_struct() {
1244 let type_ = &"0x2::foo::Bar".parse().unwrap();
1245 let addr = "0x300".parse().unwrap();
1246 let struct_ = Value::Struct(Struct {
1247 type_,
1248 fields: Fields::Named(vec![
1249 ("x", Value::U32(100)),
1250 ("y", Value::U32(200)),
1251 ("z", Value::Address(Address::latest(addr))),
1252 ]),
1253 });
1254
1255 assert_eq!(
1256 bcs::to_bytes(&struct_).unwrap(),
1257 bcs::to_bytes(&(100u32, 200u32, addr)).unwrap()
1258 );
1259 }
1260
1261 #[test]
1262 fn test_serialize_empty_struct() {
1263 let type_ = &"0x2::foo::Empty".parse().unwrap();
1264
1265 let positional = Value::Struct(Struct {
1266 type_,
1267 fields: Fields::Positional(vec![]),
1268 });
1269
1270 let named = Value::Struct(Struct {
1271 type_,
1272 fields: Fields::Named(vec![]),
1273 });
1274
1275 assert_eq!(
1276 bcs::to_bytes(&positional).unwrap(),
1277 bcs::to_bytes(&false).unwrap()
1278 );
1279
1280 assert_eq!(
1281 bcs::to_bytes(&named).unwrap(),
1282 bcs::to_bytes(&false).unwrap()
1283 );
1284 }
1285
1286 #[test]
1287 fn test_serialize_enum() {
1288 #[derive(Serialize)]
1289 enum E {
1290 A(u64, bool),
1291 B { x: u32, y: u32 },
1292 C,
1293 }
1294
1295 let type_: StructTag = "0x1::m::E".parse().unwrap();
1296 let enum_ = Value::Enum(Enum {
1297 type_: &type_,
1298 variant_name: Some("A"),
1299 variant_index: 0,
1300 fields: Fields::Positional(vec![Value::U64(42), Value::Bool(true)]),
1301 });
1302
1303 assert_eq!(
1304 bcs::to_bytes(&enum_).unwrap(),
1305 bcs::to_bytes(&E::A(42, true)).unwrap()
1306 );
1307
1308 let enum_ = Value::Enum(Enum {
1310 type_: &type_,
1311 variant_name: Some("B"),
1312 variant_index: 1,
1313 fields: Fields::Named(vec![("x", Value::U32(100)), ("y", Value::U32(200))]),
1314 });
1315
1316 assert_eq!(
1317 bcs::to_bytes(&enum_).unwrap(),
1318 bcs::to_bytes(&E::B { x: 100, y: 200 }).unwrap()
1319 );
1320
1321 let enum_ = Value::Enum(Enum {
1323 type_: &type_,
1324 variant_name: Some("C"),
1325 variant_index: 2,
1326 fields: Fields::Positional(vec![]),
1327 });
1328
1329 assert_eq!(
1330 bcs::to_bytes(&enum_).unwrap(),
1331 bcs::to_bytes(&E::C).unwrap()
1332 );
1333 }
1334
1335 #[test]
1336 fn test_serialize_vector() {
1337 let vec = Value::Vector(Vector {
1338 type_: Cow::Owned(TypeTag::U64),
1339 elements: vec![Value::U64(10), Value::U64(20), Value::U64(30)],
1340 });
1341
1342 assert_eq!(
1343 bcs::to_bytes(&vec).unwrap(),
1344 bcs::to_bytes(&vec![10u64, 20, 30]).unwrap()
1345 );
1346
1347 let vec = Value::Vector(Vector {
1349 type_: Cow::Owned(TypeTag::Struct(Box::new(StructTag {
1350 address: MOVE_STDLIB_ADDRESS,
1351 module: STD_ASCII_MODULE_NAME.to_owned(),
1352 name: STD_ASCII_STRUCT_NAME.to_owned(),
1353 type_params: vec![],
1354 }))),
1355 elements: vec![
1356 Value::String(Cow::Borrowed("hello".as_bytes())),
1357 Value::String(Cow::Borrowed("world".as_bytes())),
1358 ],
1359 });
1360
1361 assert_eq!(
1362 bcs::to_bytes(&vec).unwrap(),
1363 bcs::to_bytes(&vec!["hello", "world"]).unwrap()
1364 );
1365
1366 let vec = Value::Vector(Vector {
1368 type_: Cow::Owned(TypeTag::U64),
1369 elements: vec![],
1370 });
1371
1372 assert_eq!(bcs::to_bytes(&vec).unwrap(), &[0x00]);
1373 }
1374
1375 #[test]
1376 fn test_literal_to_atom_conversion() {
1377 let values = vec![
1378 Value::Bool(true),
1379 Value::U8(42),
1380 Value::U16(1234),
1381 Value::U32(123456),
1382 Value::U64(12345678),
1383 Value::U128(123456),
1384 Value::U256(U256::from(42u64)),
1385 Value::Address(Address::latest("0x42".parse().unwrap())),
1386 Value::String(Cow::Borrowed("hello".as_bytes())),
1387 Value::Bytes(Cow::Borrowed(&[1, 2, 3])),
1388 Value::Vector(Vector {
1389 type_: Cow::Owned(TypeTag::U8),
1390 elements: vec![
1391 Value::U8(4),
1392 Value::U8(5),
1393 Value::Slice(Slice {
1394 layout: &L::U8,
1395 bytes: &[6],
1396 scoped: false,
1397 }),
1398 ],
1399 }),
1400 ];
1401
1402 let atoms = vec![
1403 Atom::Bool(true),
1404 Atom::U8(42),
1405 Atom::U16(1234),
1406 Atom::U32(123456),
1407 Atom::U64(12345678),
1408 Atom::U128(123456),
1409 Atom::U256(U256::from(42u64)),
1410 Atom::Address("0x42".parse().unwrap()),
1411 Atom::Bytes(Cow::Borrowed("hello".as_bytes())),
1412 Atom::Bytes(Cow::Borrowed(&[1, 2, 3])),
1413 Atom::Bytes(Cow::Borrowed(&[4, 5, 6])),
1414 ];
1415
1416 for (value, expect) in values.into_iter().zip_eq(atoms) {
1417 let actual = Atom::try_from(value).unwrap();
1418 assert_eq!(actual, expect);
1419 }
1420 }
1421
1422 #[test]
1423 fn test_slice_to_atom_converion() {
1424 let bool_bytes = bcs::to_bytes(&true).unwrap();
1425 let u8_bytes = bcs::to_bytes(&42u8).unwrap();
1426 let u16_bytes = bcs::to_bytes(&1234u16).unwrap();
1427 let u32_bytes = bcs::to_bytes(&123456u32).unwrap();
1428 let u64_bytes = bcs::to_bytes(&12345678u64).unwrap();
1429 let u128_bytes = bcs::to_bytes(&123456u128).unwrap();
1430 let u256_bytes = bcs::to_bytes(&U256::from(42u64)).unwrap();
1431 let addr_bytes = bcs::to_bytes(&AccountAddress::from_str("0x42").unwrap()).unwrap();
1432 let str_bytes = bcs::to_bytes("hello").unwrap();
1433 let type_name_bytes = bcs::to_bytes("0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>").unwrap();
1434 let vec_bytes = bcs::to_bytes(&vec![1u8, 2, 3]).unwrap();
1435
1436 let str_layout = L::Struct(Box::new(move_utf8_str_layout()));
1437 let type_name_layout = L::Struct(Box::new(type_name_layout()));
1438 let vec_layout = L::Vector(Box::new(L::U8));
1439
1440 let values = vec![
1441 Value::Slice(Slice {
1442 layout: &L::Bool,
1443 bytes: &bool_bytes,
1444 scoped: false,
1445 }),
1446 Value::Slice(Slice {
1447 layout: &L::U8,
1448 bytes: &u8_bytes,
1449 scoped: false,
1450 }),
1451 Value::Slice(Slice {
1452 layout: &L::U16,
1453 bytes: &u16_bytes,
1454 scoped: false,
1455 }),
1456 Value::Slice(Slice {
1457 layout: &L::U32,
1458 bytes: &u32_bytes,
1459 scoped: false,
1460 }),
1461 Value::Slice(Slice {
1462 layout: &L::U64,
1463 bytes: &u64_bytes,
1464 scoped: false,
1465 }),
1466 Value::Slice(Slice {
1467 layout: &L::U128,
1468 bytes: &u128_bytes,
1469 scoped: false,
1470 }),
1471 Value::Slice(Slice {
1472 layout: &L::U256,
1473 bytes: &u256_bytes,
1474 scoped: false,
1475 }),
1476 Value::Slice(Slice {
1477 layout: &L::Address,
1478 bytes: &addr_bytes,
1479 scoped: false,
1480 }),
1481 Value::Slice(Slice {
1482 layout: &str_layout,
1483 bytes: &str_bytes,
1484 scoped: false,
1485 }),
1486 Value::Slice(Slice {
1487 layout: &type_name_layout,
1488 bytes: &type_name_bytes,
1489 scoped: false,
1490 }),
1491 Value::Slice(Slice {
1492 layout: &vec_layout,
1493 bytes: &vec_bytes,
1494 scoped: false,
1495 }),
1496 ];
1497
1498 let atoms = vec![
1499 Atom::Bool(true),
1500 Atom::U8(42),
1501 Atom::U16(1234),
1502 Atom::U32(123456),
1503 Atom::U64(12345678),
1504 Atom::U128(123456),
1505 Atom::U256(U256::from(42u64)),
1506 Atom::Address(AccountAddress::from_str("0x42").unwrap()),
1507 Atom::Bytes(Cow::Borrowed("hello".as_bytes())),
1508 Atom::Bytes(Cow::Borrowed("0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>".as_bytes())),
1509 Atom::Bytes(Cow::Borrowed(&[1, 2, 3])),
1510 ];
1511
1512 for (value, expect) in values.into_iter().zip_eq(atoms) {
1513 let actual = Atom::try_from(value).unwrap();
1514 assert_eq!(actual, expect);
1515 }
1516 }
1517
1518 #[test]
1519 fn test_basic_json_formatting() {
1520 let values = vec![
1521 Value::Bool(true),
1522 Value::U8(42),
1523 Value::U16(43),
1524 Value::U32(44),
1525 Value::U64(45),
1526 Value::U128(46),
1527 Value::U256(U256::from(47u64)),
1528 Value::Address(Address::latest("0x48".parse().unwrap())),
1529 Value::String(Cow::Borrowed("hello".as_bytes())),
1530 Value::Bytes(Cow::Borrowed(&[1, 2, 3])),
1531 ];
1532
1533 let json = vec![
1534 json!(true),
1535 json!(42u8),
1536 json!(43u8),
1537 json!(44u8),
1538 json!("45"),
1539 json!("46"),
1540 json!("47"),
1541 json!("0x0000000000000000000000000000000000000000000000000000000000000048"),
1542 json!("hello"),
1543 json!("AQID"),
1544 ];
1545
1546 for (value, expect) in values.into_iter().zip_eq(json) {
1547 let used = AtomicUsize::new(0);
1548 let meter = writer::Meter::new(&used, usize::MAX, usize::MAX);
1549 let actual = value.format_json::<Json>(meter).unwrap();
1550 assert_eq!(actual, expect);
1551 }
1552 }
1553
1554 #[test]
1555 fn test_struct_json_formatting() {
1556 let lit = Value::Struct(Struct {
1557 type_: &"0x2::foo::Bar".parse().unwrap(),
1558 fields: Fields::Named(vec![
1559 ("x", Value::U32(100)),
1560 ("y", Value::U32(200)),
1561 (
1562 "z",
1563 Value::Address(Address::latest("0x300".parse().unwrap())),
1564 ),
1565 ]),
1566 });
1567
1568 let slice = Value::Slice(Slice {
1569 layout: &struct_(
1570 "0x2::foo::Bar",
1571 vec![("x", L::U32), ("y", L::U32), ("z", L::Address)],
1572 ),
1573 bytes: &bcs::to_bytes(&(100u32, 200u32, "0x300".parse::<AccountAddress>().unwrap()))
1574 .unwrap(),
1575 scoped: false,
1576 });
1577
1578 let expect = json!({
1579 "x": 100u32,
1580 "y": 200u32,
1581 "z": "0x0000000000000000000000000000000000000000000000000000000000000300"
1582 });
1583
1584 let used = AtomicUsize::new(0);
1585 let mut meter = writer::Meter::new(&used, usize::MAX, usize::MAX);
1586 assert_eq!(expect, lit.format_json::<Json>(meter.reborrow()).unwrap());
1587 assert_eq!(expect, slice.format_json::<Json>(meter.reborrow()).unwrap());
1588 }
1589
1590 #[test]
1591 fn test_enum_named_variant_json_formatting() {
1592 let lit = Value::Enum(Enum {
1593 type_: &"0x1::m::E".parse().unwrap(),
1594 variant_name: Some("A"),
1595 variant_index: 0,
1596 fields: Fields::Named(vec![("b", Value::U64(42)), ("c", Value::Bool(true))]),
1597 });
1598
1599 let slice = Value::Slice(Slice {
1600 layout: &enum_(
1601 "0x1::m::E",
1602 vec![("A", vec![("b", L::U64), ("c", L::Bool)])],
1603 ),
1604 bytes: &bcs::to_bytes(&(0u8, 42u64, true)).unwrap(),
1605 scoped: false,
1606 });
1607
1608 let expect = json!({
1609 "@variant": "A",
1610 "b": "42",
1611 "c": true
1612 });
1613
1614 let used = AtomicUsize::new(0);
1615 let mut meter = writer::Meter::new(&used, usize::MAX, usize::MAX);
1616 assert_eq!(expect, lit.format_json::<Json>(meter.reborrow()).unwrap());
1617 assert_eq!(expect, slice.format_json::<Json>(meter.reborrow()).unwrap());
1618 }
1619
1620 #[test]
1621 fn test_enum_numeric_variant_json_formatting() {
1622 let literal = Value::Enum(Enum {
1623 type_: &"0x1::m::E".parse().unwrap(),
1624 variant_name: None,
1625 variant_index: 0,
1626 fields: Fields::Named(vec![("b", Value::U64(42)), ("c", Value::Bool(true))]),
1627 });
1628
1629 let expect = json!({
1630 "@variant": 0,
1631 "b": "42",
1632 "c": true
1633 });
1634
1635 let used = AtomicUsize::new(0);
1636 let meter = writer::Meter::new(&used, usize::MAX, usize::MAX);
1637 assert_eq!(expect, literal.format_json::<Json>(meter).unwrap());
1638 }
1639}