Skip to main content

sui_display/v2/
value.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use 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/// Dynamically load objects by their ID, returning the object's owned data.
42///
43/// The `Store` trait is responsible only for fetching object data -- lifetime management
44/// and caching are handled by the `Interpreter`. The interpreter can potentially issue racing
45/// requests for the same object, and it is the store's responsibility to handle this correctly
46/// (e.g. by deduplicating in-flight requests).
47#[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/// Result of evaluating a single strand of a Display v2 format string.
61#[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/// Value representation used during evaluation by the Display v2 interpreter.
72#[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    /// Indicates whether this value came from the parent object being formatted (in which case
95    /// child object reads should be scoped by the parent object's version).
96    pub(crate) scoped: bool,
97}
98
99/// Non-aggregate values that can be formatted during string interpolation.
100#[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
113/// A single step in a chain of accesses, with its inner expression (if there is one) evaluated.
114pub 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/// Bytes extracted from the serialized representation of a Move value, along with its layout.
124#[derive(Copy, Clone)]
125pub struct Slice<'s> {
126    pub(crate) layout: &'s MoveTypeLayout,
127    pub(crate) bytes: &'s [u8],
128
129    /// Indicates whether this value came from the parent object being formatted (in which case
130    /// child object reads should be scoped by the parent object's version).
131    pub(crate) scoped: bool,
132}
133
134/// An owned version of `Slice`.
135#[derive(Clone)]
136pub struct OwnedSlice {
137    pub layout: MoveTypeLayout,
138    pub bytes: Vec<u8>,
139
140    /// Indicates whether this value came from the parent object being formatted (in which case
141    /// child object reads should be scoped by the parent object's version).
142    pub scoped: bool,
143}
144
145/// An evaluated vector literal.
146#[derive(Clone)]
147pub struct Vector<'s> {
148    pub(crate) type_: Cow<'s, TypeTag>,
149    pub(crate) elements: Vec<Value<'s>>,
150}
151
152/// An evaluated struct literal.
153#[derive(Clone)]
154pub struct Struct<'s> {
155    pub(crate) type_: &'s StructTag,
156    pub(crate) fields: Fields<'s>,
157}
158
159/// An evaluated enum/variant literal.
160#[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/// Evaluated fields that are part of a struct or enum literal.
169#[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    /// Treat this value as a dynamic field name, and derive the ID of its `Field<K, V>` object,
193    /// under the given `parent` address.
194    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    /// Treat this value as a dynamic object field name, and derive the ID of its `Field<K, V>`
205    /// object, under the given `parent` address.
206    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    /// Treat this value as a derived object key and derive the corresponding object ID under the
217    /// given parent address.
218    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    /// The Move type of this value.
226    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    /// Write out a formatted representation of this value, transformed by `transform`, to the
258    /// provided writer.
259    ///
260    /// This operation can fail if the transform is not supported for this value, or if the output
261    /// is too large. If it succeds, `w` will be modified to include the newly written data.
262    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    /// Write out a formatted representation of this value as JSON, using the provided meter.
283    ///
284    /// This operation can fail if the output is too large. If it succeeds, `meter` will be
285    /// modified to account for the size of the written data.
286    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    /// Attempt to coerce this value into a `u64` if that's possible. This works for any numeric
319    /// value that can be represented within 64 bits.
320    pub(crate) fn as_u64(&self) -> Option<u64> {
321        use MoveTypeLayout as L;
322        use Value as V;
323
324        match self {
325            // Numeric literals in Display
326            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            // Numeric values sliced out of Move values
334            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            // Everything else cannot be coerced to u64
349            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    /// Annotate the value with a scope status.
360    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            // Other value types can't be parents for child object reads, so scope status can be
366            // ignored.
367            _ => (),
368        }
369    }
370}
371
372impl Atom<'_> {
373    /// Format the atom as a hexadecimal string.
374    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    /// Format the atom as a string.
401    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    /// Coerce the atom into an `i64`, interpreted as an offset in milliseconds since the Unix
425    /// epoch, and format it as an ISO8601 timestamp.
426    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    /// Like string formatting, but percent-encoding reserved URL characters.
439    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    /// Base64-encode the byte representation of this atom.
465    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    /// Attempt to coerce this atom into an `i64`, if possible.
487    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    /// Coerce this accessor into a numeric index, if possible, and returns its value.
502    ///
503    /// Coercion works for all integer literals, as well as `Slice` literals with a numeric layout,
504    /// as long as their numeric values fit into a `u64`.
505    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            // All other index types don't represent a numeric index.
511            A::DFIndex(_) | A::DOFIndex(_) | A::Derived(_) | A::Field(_) | A::Positional(_) => None,
512        }
513    }
514
515    /// Coerce this accessor into a field name, if possible, and return its name.
516    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    /// Convert this value into an owned slice.
556    ///
557    /// This operation returns `None` if the value contains compound literals (struct, enum, vector
558    /// literals), since their layouts are not guaranteed to be valid.
559    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    /// Compute the type layout for this value, if possible.
576    ///
577    /// Returns `None` for compound literals (Struct, Enum, Vector) since we cannot reliably
578    /// compute their layouts without access to the full type information.
579    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            // Compound literals: cannot compute layout
598            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    /// Attempt to fetch a particular field  from a struct or enum literal's fields based on the
649    /// given accessor.
650    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
702/// Serialize implementation for Value to support serializing the Value to BCS bytes.
703impl 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
727/// This implementation makes it so that serializing a `Slice` to BCS bytes produces the bytes
728/// unchanged (but this property is not guaranteed for any other format).
729impl 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        // Serialize the struct as a tuple, regardless of whether it has named or positional
763        // fields, because `serde`'s field names need to be `&'static str`, which we don't have
764        // (and we don't need).
765        let mut s = serializer.serialize_tuple(self.fields.len())?;
766
767        match &self.fields {
768            // Move values cannot serialize to an empty byte stream, so if there are no fields,
769            // `dummy_field: bool = false` is injected.
770            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        // Serialize the enum as a tuple, with empty names, for similar reasons as `Struct`, above.
800        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            // Byte arrays and strings are indistinguishable at the Atom level
844            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            // Vector literals are supported if they are byte vectors.
850            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    /// Mock Store implementation for testing.
935    #[derive(Default, Clone)]
936    pub struct MockStore {
937        data: BTreeMap<AccountAddress, (MoveTypeLayout, Vec<u8>)>,
938    }
939
940    impl MockStore {
941        /// Add objects representing a dynamic field to the store.
942        ///
943        /// The dynamic field is owned by `parent` and has the given `name` and `value`, with their
944        /// respective layouts.
945        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        /// Add objects representing a dynamic object field to the store.
983        ///
984        /// The dynamic object field is owned by `parent` and has the given `name` and `value`,
985        /// with their respective layouts. `value` is expected to start with a UID, as it must be
986        /// an object (its type must have `key`).
987        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        /// Add a derived object to the store.
1035        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        // Test enum with named fields
1309        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        // Test enum with no fields
1322        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        // Test vector of strings
1348        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        // Test empty vector
1367        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}