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